0

I have some covid-19 data coming from a source which I can render ok. I don't control the endpoint so I take it as it comes. If the science i hear is correct for every two confirmed there may be one unconfirmed, so I want to show adds a suspected cases column alongside the confirmed cases

So I'm effectively massaging the incoming data by adding a new calculated property 1.3 times the confirmed number, cv19_actisus is the new property name

this.newShape = this.covidCases.map(res => ({...res.attributes,
  cv19_actisus: res.attributes.cv19_acti * 1.3  }) )
    this.filteredmCovid = this.newShape;

I’ve create a Stackblitz here, this works as expected except when I add the calculated property nothing renders anymore. You can see the newly added property is added by drilling down in console

Just comment in/out the three lines above to see the template renders fine before the new property is added, but when the code with the spread operator is called nothing renders but I can see the new calculated property is present for each of the 88 object/rows returned.

I thought it might be a timing issue, rendering before the data is available so I tried a reactive approach i.e. only observables and using the async pipe in the template and I tried making the data service return a hard coded object with the same shape as the endpoint.

Can someone advice me or show me a working similar example’ thanks in advance!

IDK4real
  • 757
  • 6
  • 14

2 Answers2

0

The following will solve your problem using the spread operator:

this.newShape = this.covidCases.map(res => ({attributes: {...res.attributes,
  cv19_actisus: `${Math.round(res.attributes.cv19_acti * 1.3)}` }})  )
});

Onto the why.

this.newShape = this.covidCases.map(res => ({...res.attributes,
  cv19_actisus: res.attributes.cv19_acti * 1.3  }
))

Resolves to an object that is of the type Attributes, you can test this by printing the first instance of the this.newShape.

When you print the first line of your current code, you get this:

{FID: 24, codmun: 35016, municipio: "Las Palmas de Gran Canaria" ... }

However, what you want is an object of the type Feature, which has the key attributes and is of the Attributes. This is because the filteredmCovid is of the type Feature.

IDK4real
  • 757
  • 6
  • 14
  • Thankyou, your code works but your explanation doesn't and you have not correctly explained why my code doesn’t, at least not completely for me. My code and your code both add the newly calculated property in the right place, your comments about the root of the problem are mistaken, anyone can see that by looking in the console in stackblitz, albeit the objects are not explicitly named the same. Your code is a different approach without using the spread operator, so as its my first time here I’ll wait a little longer to see if an alternative answer enlightens a little more. I'm grateful 2u. – crackoverflow Mar 10 '21 at 16:29
  • I have updated the answer with the correct explanation of the error. Please see it now. It uses the spread operator like you were originally. Basically, you were returning an object of the type `Attributes` since `{... res.attributes, x: a}` will only pass the content of the attributes, not copy the entire object. – IDK4real Mar 10 '21 at 17:27
  • Your clarification has made has made it a great deal easier to understand. As a few have viewed this I'll add a stackblitz to show it working in case this helps anyone else, thanks again – crackoverflow Mar 12 '21 at 13:51
  • Btw please comment but I thinks it helps understanding to say the code is creating it and assigning it in one go, not just assigning the value to the prop. The prop only exists in the model as an optional property because the TypeScript runtime (our design time environment) requires it. The emphasis here is a little more on the data, the property doesn’t exist until we add it (to an array copy) and when we do that we assign a value to it. T'Script doesn’t let you add a property to incoming data unless you first define it in your model, unlike the resulting JS which does; updated Stackbiltz – crackoverflow Mar 15 '21 at 13:58
0

If i understand good you want to change or add one attributes for each res and you want to clone each res to avoid to mutate data ?

For me the problem comes from data returned by your map. Your input is : Array<{attributes: {codenum, .....;}> and your output is Array<{codenume, .....}>.

I suggest you this code :

    this.newShape = this.covidCases.map(res => {
      const attributes = {
        ...res.attributes,
        cv19_actisus: `${Math.round(res.attributes.cv19_acti * 1.3)}`
      };
      return { ...res, attributes };
    });
  • I am adding a property to each of the objects in the array named attributes, if you make a get request with the url in the api-urls.service.ts in the C19 folder, you’ll see what’s returned; I’m only interested in Features property which itself has only one property called attributes which is an array of objects each of which I want to add a new calculated property to each one. I 'm using the spread operator (this is one of its many recommended uses) and I can see it works in the console. If you try IDK4Real code you will also see the prop is added, so please where did you see codemun-codmune – crackoverflow Mar 10 '21 at 16:46