AngularJS rendering takes a lot of time - javascript

I've got a model that's like this:
{
"items": [
{
"type": "A",
"id": "2",
"number": 0,
"info": "info1",
"childs": [
{
"type": "B",
"id": "21",
"number": 0,
"info": "info1",
"childs": []
}
]
},
{
"type": "A",
"id": "1",
"number": 0,
"info": "info1",
"childs": []
},
{
"type": "A",
"id": "2",
"number": 0,
"childs": [
{
"type": "B",
"id": "21",
"number": 0,
"info": "info1",
"childs": [
{
"type": "C",
"id": "211",
"number": 0,
"info": "info1",
"childs": [
{
"type": "B",
"id": "2111",
"info": "info1",
"number": 0
}
]
}
]
}
]
}
]
}
that is rendered in the page via 4 nested ng-repeat. The property number is changed via an input="number", one for each row. The info value is changed by a selectbox
The structure is like this.
<div ng-repeat="item in items">
<input type="number" ng-model="item.number" />
<select ng-model="item.info">
</select>
<div ng-repeat="child in items.child">
<input type="number" ng-model="child.number" />
<select ng-model="child.info">
</select>
<div ng-repeat="child2 in child.child">
<input type="number" ng-model="child2.number" />
<select ng-model="child2.info">
</select>
<div ng-repeat="child3 in child2.child">
<input type="number" ng-model="child3.number" />
<select ng-model="child3.info">
</select>
</div>
</div>
</div>
</div>
Well that's not exactly how's the actual webapp but it's enough for you. Anyway, if I change the value of an input="number", the rendering process takes like 1500ms to complete. The same (but the rendering is a little bit faster) happens when I change the selectbox selected option.
When I change the value I just need to update the property of the item in the model. Why does angular render all over again?
What can I do?
Keep in mind that usually the model contains around 10/15 items with 5 to 20 child each.
PS: Weird thing, when I change the input value clicking on the spinners (the default ones that appear when I use Chrome), the number is incremented or decremented by 2, and not 1.
EDIT: Still haven't solved this problem. When I have too many items to display in the screen, all the rendering process is too slow with four nested ng-repeat. Anyone has an alternative solution for display my model in the page and modify the values without losing 2s on rendering? I can't use pagination or infinite scrolling.

Related

JSON weird format access data

This is a JSON snip that is created in WooCommerce by a plugin that adds some metadata. I cannot change the formatting of this JSON because it is generated by a plugin. The problem is that the keys and the values are added in a weird way. I am iterating through the line_items and statically referencing this data which I don't want to do, I would like to know if there is a smart way to reference for example:
"key": "_cpo_product_id",
"value": "3572",
if this was formatted correctly it would be: "_cpo_product_id": "3572" and not have "value" as a key, and it would be accessed by: foo.line_items[i]._cpo_product_id
but with this configuration I am a bit lost, I am sure there is an easy way to find the value for a specific key. I am doing this on Google app scripts, but a solution in JavaScript should suffice.
JSON snip:
"line_items": [
{
"id": 749,
"name": "Dune",
"product_id": 3572,
"variation_id": 0,
"quantity": 1,
"tax_class": "",
"subtotal": "149.54",
"subtotal_tax": "31.40",
"total": "149.54",
"total_tax": "31.40",
"taxes": [
{
"id": 24,
"total": "31.403148",
"subtotal": "31.403148"
}
],
"meta_data": [
{
"id": 11919,
"key": "_cpo_product_id",
"value": "3572",
"display_key": "_cpo_product_id",
"display_value": "3572"
},
{
"id": 11920,
"key": "_add-to-cart",
"value": "3572",
"display_key": "_add-to-cart",
"display_value": "3572"
},

VueJS sum pivot table

I am learning VueJS and am in the process of porting a very simple app I wrote in Laravel with blade as the template engine.
I am keeping the existing back end which consists of a simple restful api of 3 tables: Books, Places and a pivot Books_Places.
The json looks something like this:
books:
{
"id": 1,
"title": "foo bar",
"places": [
{
"id": 1,
"name": "library 1",
"pivot": {
"book_id": "1",
"place_id": "1",
"quantity": "50",
"id": 1
}
},
{
"id": 2,
"name": "library 2",
"pivot": {
"book_id": "1",
"place_id": "2",
"quantity": "75",
"id": 2
}
}
]
}
In blade I had the following line built into a "for book in books" cycle which I loved because of its simplicity:
{{ $book->places->sum('pivot.quantity') }}
I am trying to accomplish the same in VueJS but not sure what the simplest approach is, I'd appreciate your opinions.
Thanks!
You could create a method to sum up the quantities using Array#reduce:
methods: {
sumOfQuantities: function(book) {
return book.places.reduce(function(sum, next) {
return sum + Number(next.pivot.quantity);
}, 0);
}
}
Note: Since your quantity is a string, you need to convert it to a Number (e.g. using Number()).
You can then access it in your template using v-text for example:
<div v-for="book in books">
<div v-text="sumOfQuantities(book)"></div>
</div>

JSON and AngularJS (trying to figure out the ng-repeat part)

So I have this on my JSON file:
[{
"title": "Secondary Containment",
"products": {
"product": [
{
"id": "1001",
"name": "one"
},
{
"id": "1002",
"name": "two"
},
{
"id": "1003",
"name": "three"
}
]
}
}, {
"title": "Another Title",
"products": {
"product": [
{
"id": "1011",
"name": "alpha"
},
{
"id": "1012",
"name": "beta"
},
{
"id": "1013",
"name": "gamma"
}
]
}
}]
What would I include in my ng-repeat to repeat the id's of the products in a list?
I have ng-repeat="category in categories" in my outer container which is repeating the different titles {{category.title}} but it's not repeating the inner array and nothing shows up when i try outputting {{category.products.product.id}}
Any ideas?
You need nested ng-repeat
<div ng-repeat="category in categories">
<div ng-repeat="product in category.products.product">
{{product.id}}
</div>
</div>
Your html should be
<div data-ng-repeat="category in categories">
<div data-ng-repeat="product in category.products.product">
{{product.id}}
</div>
</div>
You can do as nikhil said. But you need nested ng-repeat. But I personally suggest to use data-ng-repeat instead ng-repeat. The only main reason to use data-ng-* is The data-ng-* allows the HTML to be validated through validators that do not understand Angular

How to create a custom filter to search on nested arrays on Angular 1.3.6?

I have this array sports, json looks like:
[
{
"id": 26,
"name": "LIVE Betting",
"priority": 0,
"leagues": []
},
{
"id": 8,
"name": "NBA",
"priority": 3,
"leagues": [
{
"id": 5932,
"parent": 1000,
"name": "NBA",
"sport": {
"id": 8,
"name": "NBA"
},
"lineType": "G",
"priority": [
1,
3
],
"part": "0"
}
]
},
{
"id": 24,
"name": "College Basketball",
"priority": 4,
"leagues": [
{
"id": 2599,
"parent": 1000,
"name": "NCAA BASKETBALL",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
0,
4
],
"part": "0"
},
{
"id": 2631,
"parent": 1000,
"name": "NCAA BASKETBALL ADDED GAMES",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
1,
4
],
"part": "0"
},
...
within that array you can see other array named "leagues": [{...}] which contains an Object, my filter is searching fine through the top array which is sports but once I try to find through the "name" within leagues array then my app shows up a message that the filter is empty.
I just realized that this is happening because I am using the version 1.3.6 of Angular but I am unable to change it until the Ionic people upgrade it to the 1.3.8, I made this Plnkr with the version 1.3.8 and it works properly, but if you change the version on that same Plnkr to the 1.3.6 automatically stop searching through leagues.name and only works with sport.name, and here is a Plnkr with the version 1.3.6, on both Plnkrs try searching Greece, in the first with the version 1.3.8 works, but in the version 1.3.6 just the message no sports to show comes up
<input type="search" ng-model="query">
<div ng-repeat="sport in sportsFilter = (sports | filter:query)">
<!--this array works fine-->
<strong>{{sport.name}}</strong>
</div>
<div ng-repeat="league in sport.leagues">
<!--this one not works at all-->
{{league.name}}
</div>
</div>
I've been trying all the ways already, with a resolve, with different models, etc and actually I just realized that I need a custom filter so I would like you to give me a hand because I do not where to start from with it.
or is there any easier way ?
<div ng-app="myApp">
<div ng-controller="TestController">
<input type="search" placeholder="Search" ng-model="query">
<div role="alert" ng-show="sportfilter.length==0">No sports to show</div>
<div ng-repeat="sport in sportfilter=(sports | filter:matchNameDeep(query))" ng-show="sport.leagues.length">
<div>
<strong>{{sport.name}}</strong>
</div>
<div class="item item-button-right" ng-repeat="league in sport.leagues" on-tap="goToLines(league)">
{{league.name}}
</div>
</div>
</div>
</div>
$scope.matchNameDeep = function(query) {
return function(sport) {
return !query || sport.name.match(new RegExp(query, "ig")) || sport.leagues.some(function(element, index, array) {
return element.name.match(new RegExp(query, "ig"))
});
}
};
see here it working with angular 1.3.6 http://plnkr.co/edit/0w9PYbDsOz0mHBdVldZt?p=preview
You can use https://github.com/marklagendijk/lodash-deep for this type of thing.

How to display observable in html binding with empty container knockoutjs

I have an array like this which i am trying to bind with a select.
var arr = [{
"Id": 1,
"Rate": 5,
"Price": 200,
"Name": "History",
"template": "<option id='1'>History</option>"
}, {
"Id": 2,
"Rate": 5,
"Price": 150,
"Name": "Geographic",
"template": "<option id='2'>Geographic</option>"
}, {
"Id": 3,
"Rate": 1,
"Price": 75,
"Name": "Maths",
"template": "<option id='3'>Maths</option>"
}, {
"Id": 4,
"Rate": 2,
"Price": 50,
"Name": "Statistics",
"template": "<option id='4'>Statistics</option>"
}, {
"Id": 5,
"Rate": 3,
"Price": 120,
"Name": "Drawing",
"template": "<option id='5'>Drawing</option>"
}]
As you can see there is template which contains a string for option. This i have created with some function. Now i want to bind this array to select.
self.Result = ko.observableArray(arr)
View
<select data-bind="foreach:Result">
<!-- ko html:$data.template -->
<!-- /ko -->
</select>
And now it produces an error. html binding can not be used with virtual elements.
Moreover if i try this
ko.virtualElements.allowedBindings.html = true;
It does not solve the problem as i assume it is only for custom bindings.
Is there any solution for this? What should i do if i need to procees with this
On solution would be to directly use the html binding on the select element and manually concatenate your template to one string:
<select data-bind="html: Result.map(function(i) { return i.template }).join('\n')">
</select>
Demo JSFiddle.
However if you could then you should change your design and not send back the template html but build it on the client:
<select data-bind="foreach:Result">
<option data-bind="attr: {id: Id}, text: Name"></option>
</select>
Demo JSFiddle.
Thanks for the solution #nemesv provided i came to this point
self.LoadTemplate = function(){
return self.Result().map(function(i) { return i.template }).join('\n')
}
And
<select data-bind="html:LoadTemplate()"></select>
Still i would like html binding to support virtual elements.

Categories

Resources