I have a Backbone Collection of Models that have different data coming in on page load than when it's fetched.
For example, the attributes coming in on page load are:
[{ name: 'cat', color: 'yellow' },
{ name: 'dog', color: 'brown' },
{ name: 'fish', color: 'orange' }]
Then, on fetch() (or otherwise updated from the server while the page lives, the data looks like:
[{ name: 'cat', current: 5, total: 100 },
{ name: 'dog', current: 6, total: 50 },
{ name: 'fish', current:7, total: 25 }]
How can I update the Backbone Collection with the new data while retaining the old data? IDs are not assigned from the server (name is guaranteed unique).
I ended up going with this. This will update the properties for models that exist while also removing models that did not come in and adding new ones.
Backbone.Collection.prototype.update = function(col_in){
var self = this,
new_models = [];
_(col_in).each(function(mod_in) {
var new_model = self._prepareModel(mod_in),
mod = self.get(new_model.id);
if (mod) {
new_models.push(mod.set(mod_in, {silent:true}));
} else {
new_models.push(mod_in);
}
});
this.reset(new_models);
};
Note the use of _prepareModel this is important so that the Models can be identified via whatever "id" property is used in the Backbone Model object.
Related
Given the script below below:
//just a dummy data source for our list
import { healthModel } from './healthModel';
export const healthListAll: healthModel[] =
[
{
id: 1,
Name: 'Asparagus',
healthGroup: 'Vegetable',
isAvail: 1
},
{
id: 2,
Name: 'Banana',
healthGroup: 'Fruit',
isAvail: 0
},
{
id: 3,
Name: 'Pomegranate',
healthGroup: 'Fruit',
isAvail: 1
},
{
id: 2,
Name: 'Artichoke',
healthGroup: 'Vegetable',
isAvail: 0
}
]
on the ts component I can do healthList = healthListAll;
So I can get the total count on the html component via
{{healthList.length}}
However, is there a way for me to only get the length of items where
isAvail = 0 or by healthGroup? can I do it on html component so it's clean?
or could it be only done on the ts component?
Apologies. Quite new to angular.
To get get the length of items where isAvail = 0 or by healthGroup you have to do it in your ts
var length=this.healthListAll.filter(x=>x.isAvil==0).length
var length=this.healthListAll.filter(x=>x.healthGroup=='Fruit').length
The template is not capable to do that so you can only apply filter, sort, etc... logic in your component then you can binding the data to the template using interpolation.
Hope it help.
Our GraphQL server responds to a query with data that includes an array of objects each of which shares the same id and different values for a different key. For instance, we might have an array that looks like:
[
{ id: 123, name: 'foo', type: 'bar', cost: 5 },
{ id: 123, name: 'foo', type: 'bar', cost: 6 },
{ id: 123, name: 'foo', type: 'bar', cost: 7 },
{ id: 123, name: 'foo', type: 'bar', cost: 8 }
]
We can see in the Network tab that the response from the server has the correct data in it. However, by the time it goes through processing by the Apollo Client module the array has been transformed into something that might look like this:
[
{ id: 123, name: 'foo', type: 'bar', cost: 5 },
{ id: 123, name: 'foo', type: 'bar', cost: 5 },
{ id: 123, name: 'foo', type: 'bar', cost: 5 },
{ id: 123, name: 'foo', type: 'bar', cost: 5 }
]
Essentially what we're seeing is that if all of the objects in an array share the same value for id then all objects in the array become copies of the first object in the array.
Is this the intended behavior of Apollo Client? We thought maybe it had something to do with incorrect caching, but we were also wondering if maybe Apollo Client assumed that subsequent array members with the same id were the same object.
It looks like this is behavior as intended. The Apollo Client normalizes on id.
As the other answer suggests this happens because Apollo normalises by ID. There's a very extensive article on the official blog that explains the rationale of it, along with the underlying mechanisms.
In short, as seen by Apollo's cache, your array of objects contains 4 instances of the same Object (id 123). Same ID, same object.
This is a fair assumption on Apollo's side, but not so much in your case.
You have to explicitly tell Apollo that these are indeed 4 different items that should be treated differently.
In the past we used dataIdFromObject, and you can see an example here.
Today, you would use typePolicies and keyfields:
const cache = new InMemoryCache({
typePolicies: {
YourItem: {
// Combine the fields that make your item unique
keyFields: ['id', 'cost'],
}
},
});
Docs
It works for me:
const cache: InMemoryCache = new InMemoryCache({ dataIdFromObject: o => false )};
previous answer solves this problem too!
Also you can change the key name(for example id => itemId) on back-end side and there won't be any issue!
I have the same issue. My solution is to set fetchPolicy: "no-cache" just for this single API so you don't have to change the InMemoryCache.
Note that setting fetchPolicy to network-only is insufficient because it still uses the cache.
fetchPolicy document
I am working on a application which is nicely modularized using requirejs. One of the modules called data service is in charge of providing other modules with data. Pretty much all get* methods of this module return javascript script objects in the the following format:
res = {
totalRows: 537,
pageSize: 10,
page: 15,
rows: [
{
id: 1,
name: 'Angelina'
...
},
{
id: 2,
name: 'Halle'
...
},
{
id: 3,
name: 'Scarlet'
...
},
{
id: 4,
name: 'Rihanna'
...
},
{
id: 5,
name: 'Shakira'
...
},
....
//10 rows
{
id: 10,
name: 'Kate'
...
}
]
}
Is it possible to initialize the data table by providing it with rows for the current page, current page number, page size and the total number of records or pages so that it "knows" which page is currently being displayed as well as the number of available pages. Which in turn would allow the DT to build the pager correctly allowing the user to navigate to other pages in which case we would make another call to data service module to retrieve data from the database for the selected page.
I have a $scope collection that is continually being updated through websockets, so data is coming in about every 2 seconds.
Let's say I have this data coming in,
var socketData = [{
name: 'bob',
age: '20',
color: 'red'
}, {
name: 'jack',
age: '10',
color: 'yellow'
}]
$scope.data = socketData;
and it's changing constantly, like this for example, which could happen a number of seconds later.
var socketData = [{
name: 'bob',
age: '21',
color: 'green'
}, {
name: 'sam',
age: '22',
color: 'red'
}]
$scope.data = socketData;
and in the DOM I have this
<div ng-repeat="d in data">
<p>{{d.name}}</p>
<p>{{d.age}}</p>
<p>{{d.color}}</p>
</div>
I would like to animate (by adding a class and just having it fade in) to each property that has changed.
By using $watch, I can get the changes, but only the objects as a whole.
$scope.$watch('data', function(newVal, oldVal) {
console.log(newVal) // whole object
console.log(oldVal) // whole object
}, true);
So the problem is that I dont want to animate the entire object, but rather the property itself. So if the name changed for each object, in the dom I'd like to see the name fields change, not an entire object, just that individual change, and I'm having a difficult time achieving that.
I would like to generate this array in a JavaScript file
var sports = [{ id: 1, value: "Baseball" },
{ id: 2, value: "Soccer" },
{ id: 3, value: "Basketball" },
{ id: 4, value: "Volleyball" },
{ id: 5, value: "Tennis" },
{ id: 6, value: "Running" },
{ id: 7, value: "Swimming" },
{ id: 8, value: "Tournament"}];
I have started with:
var sports = db.Sports;
But now I am stuck on how to include this in a JavaScript file. Does .net have embedded JavaScript file like Rails do?
You'll need to just retrieve the data and serialize it into javascript. If those two are the only columns, you can do a straight serialization with JavaScriptSerializer or JSON.NET. If not, you'll need to convert them, maybe something like (using JSON.NET):
var x = db.Sports.Select(s => new { id = s.id, value = s.value }).ToArray();
string json = JsonConvert.SerializeObject(x);
Once you have this JSON string, you can dump it onto a page however you want, or write it directly to the response.
If you need to know a specific way to do this part, we'd need more details (WebForms or MVC, inside a page or a separate javascript resource, etc.)
EDIT:
Adding it to the view once it's in the ViewBag is straightforward. Inside your script on the view:
var sports = #Html.Raw(ViewBag.Sports);
// or if you're not using Razor:
var sports = <%= ViewBag.Sports %>;
Since ViewBag.Sports is already properly serialized, you don't need to worry about quotation marks or brackets.