Tips for incorporating a personalized polyfill into your angular-cli development project

My current requirement involves sorting collections easily, and I have decided to extend the Array primitive for this purpose. While I understand that extending built-in objects like Array is generally discouraged, it will only be used internally and not shared as a library. Despite multiple attempts with different approaches, I am unable to achieve the desired outcome, even though the function behaves correctly as expected in the TypeScript playground.

I initially attempted to add the polyfill directly in the /src/polyfills.ts file. However, this led to a "TypeError: Attempted to assign to readonly property" error in the console when invoking the $sortBy method...

declare global {
  interface Array<T> {
    $sortBy(sortKey:string): T[];
  }
}

if (!Array.prototype['$sortBy']) {

  Object.defineProperty(Array.prototype, '$sortBy', {
    value: function(sortKey) {
      return this.sort( function(a, b) { // TypeError here???
        if (a[sortKey] < b[sortKey]) { return -1; }
        if (a[sortKey] > b[sortKey]) { return 1; }
        return 0;
      });
    }
  })

}

Another approach I explored was adding a plain JavaScript version via npm and importing it, which resulted in the same type error. What could be causing this issue?

/node_modules/my-polyfills/sortBy.js

if (!Array.prototype.$sortBy) {
  Object.defineProperties(Array.prototype, {
    '$sortBy': {
      value: function (sortKey) {
        return this.sort(function (a, b) {
          if (a[sortKey] < b[sortKey]) {
            return -1;
          }
          if (a[sortKey] > b[sortKey]) {
            return 1;
          }
          return 0;
        });
      }
    }
  });
}

.angular-cli.json

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": { ... },
  "apps": [
    {
      ...,
      "scripts": [
        "../node_modules/my-polyfills/sortBy.js",
        "../node_modules/moment/moment.js"
      ],
      ...
    }
  ],
  ...
}

Answer №1

After creating an Angular CLI 1.0.0 application, I encountered a situation where despite the version not being the cause of the issue, integrating the following code snippet into src/polyfills.ts resolved the problem:

declare global {
  interface Array<T> {
    $sortBy(sortKey:string): T[];
  }
}

if (!Array.prototype['$sortBy']) {

  Object.defineProperty(Array.prototype, '$sortBy', {
    value: function(sortKey) {
      return this.sort( function(a, b) { // TypeError here???
        if (a[sortKey] < b[sortKey]) { return -1; }
        if (a[sortKey] > b[sortKey]) { return 1; }
        return 0;
      });
    }
  })
}

In one of my components, I incorporated the following code:

var a = [1,2,3];
var b = a.$sortBy('');
console.log(b)

No errors were displayed in the console and array a was output correctly.

The root of your issue might be due to having both the aforementioned code section in your src/polyfills.ts file AND also including the same polyfill in

/node_modules/my-polyfills/sortBy.js
, which you then added to the scripts section of your .angular-cli.

You should choose one method or the other, but not both. It is advisable to go with the former, placing it in its own separate file rather than appending it to polyfills.ts

The error message

TypeError: Attempted to assign to readonly property
occurs when attempting to modify a non-writable property. Through using Object.defineProperty, you are making $sortBy read-only. By declaring Arrays.prototype.$sortBy and then trying to alter that declaration by assigning it to a new function, the error is triggered.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

bidirectional binding for a form with multiple options to select

I am working with a multiple select form in my Angular application: <mat-form-field> <mat-label>Toppings</mat-label> <mat-select [(value)]="selected" multiple> <mat-option *ngFor="let topping of toppings" [va ...

Duplicate Subscription Issue with Angular Material Flex MediaObserver

Utilizing Material Flex Layout for screen size detection, I encountered a peculiar issue where the subscribed result was appearing twice. Interestingly, the same code in another Angular project produced the expected outcome. constructor( public mediaO ...

Unable to modify state upon submission of a form

I am facing an issue where I need to update the state on the main page, but the values are updated three levels down... This particular component is responsible for fetching all the cities, storing the data in the State, and then mapping through the citie ...

Getter and Setter Implementation in Typescript without Using Classes

Check out these various SO questions discussing Typescript getters/setters: from 2015, Jan 2018, Sept 2018, and more. Now, the question arises - what is the best approach to define Typescript types for getters/setters in a plain JavaScript object without ...

Typescript failing to verify the data within an object being extended to fulfill a type

In my coding project, I have defined an initial interface called IThing, which serves as the base for several other interfaces such as IThingA, IThingB, and more. interface IThing{ id: string; } interface IThingA extends IThing{ a1: string; a2 ...

Potential undefined objects in Angular unit testing

While working on unit testing, I encountered the following error: 'Object is possibly 'undefined'' it('should set the dataSource filter to the provided argument', () => { component.applyFilter('filterValue') ...

Exploring the endless possibilities: Testing a never-ending stream using Jasmine Marbles

When working with my Angular service, I have implemented code that utilizes polling to display a spinner until a specific condition is met: @Inject({…}) export class SomeService { backendCall(): Observable<SomeStatusWrapper> { return this.htt ...

What is the process for arranging input field labels and text boxes in a table format using Angular 7?

I am looking to dynamically populate input fields labels and text boxes within an HTML form presented in a table format. Each row will have 3 columns, with the objective of displaying 3 separate text boxes in different cells for each row in my Angular 7 ap ...

Enhancing responsiveness in the auto-suggest feature

I am struggling to update the added value in the DOM after pushing a new element into the array of options. Despite my efforts, the update is not reflecting in the DOM. import { Component, OnInit } from '@angular/core'; import { FormControl } fro ...

Using Mongoose with TypeScript: Receiving an error message stating "Expected 0 arguments, but received 1" while trying to construct an ObjectId... surprisingly,

Encountering an issue where I receive the error message "Expected 0 arguments, but got 1" on this line (idProduct is a string) : |new mongoose.Types.ObjectId(idProduct) Interestingly, even though it's underlined, the code still functions correctly.. ...

Can you explain the distinction between needing ts-node and ts-node/register?

Currently, I am conducting end-to-end tests for an Angular application using Protractor and TypeScript. As I was setting up the environment, I came across the requirement to include: require("ts-node/register") Given my limited experience with Node.js, I ...

Angular BehaviorSubject is not refreshing quickly enough

After following a tutorial on creating full Angular + JWT Authentication, I encountered some issues when testing the project. In order to notify the AuthGuard that I am connected and can proceed to the next page upon logging in, I needed to send the API re ...

``Is there a specific location where I can access the Microsoft Azure msal sign-up feature within Angular

My current Angular version is 5.2.0 and I am struggling to find a tutorial on how to incorporate Azure MSAL for new user sign-up using a Microsoft account. If anyone has any resources or examples on how to achieve this integration without having to update ...

Remove all subscribers from the Observable

I'm relatively new to using Observables and Typescript, so bear with me if this question sounds like a beginner one. I am trying to create a simple timer but I want the ability to unsubscribe all subscribers from within the timer itself. Here is what ...

Next.js allows for the wrapping of a server component within a client component, seamlessly

I am currently working on a project where I have implemented a form to add data to a JSON using GraphQL and Apollo Client. The project is built with TypeScript and Next.js/React. However, I am facing a conflicting error regarding server client components ...

How to retrieve the last item in a component using *ngFor in Angular 6

How can I access the last value of *ngFor in Angular 6 and perform an operation if the last value is set? For example: <li [ngClass]="list.mydata==1?'replies a':'sent a'" *ngFor="let list of chatlist; let last=last;"> <sp ...

The Angular AutoComplete feature is displaying the value as [Object Object]

In order to display the selected value in the input box and retrieve both the selected ID and value in the .ts file, I decided to bind the option value directly to [value]. However, this caused it to be printed as [Object Object] which was not my desired o ...

The font appears distinct on the website compared to how it is displayed on the Google Fonts

I recently encountered an issue with the 'Josefin Sans' font on a website I'm building using TailwindCSS, NextJS, and Typescript. The font appears different than expected, varying from my Figma design wireframe and the Google fonts sample. H ...

Utilizing the slice method within an ngFor loop in Angular for multiple iterations

Looking to divide the nested ngfor loop into 3 sections <div class="row" *ngFor="let row of matrix; index as i"> <div class="col" *ngFor="let col of row; index as j"> <div *ngFor="let placeho ...

Tips for showing a preview of the image chosen in Angular

How can I use Angular to display a preview of the selected image? Currently, when we click, all images are selected. Does anyone have suggestions on how to show the preview of only the selected image and unselect the previously selected one when a new imag ...