I have a HTML fragment that iterates over key, value collection. When I create an object and put some value in, then iterate trough that object via HTML fragment, all works perfectly.
However since I need keys in specific order, I'm using a Map instead of plain object. This time when I debug I can see that my insertion order was preserved, but for some reason the HTML fragment which iterates over collection doesn't seem to know how to do so. I see nothing on my screen when I use the map object, opposed to the regular object when I see unordered content
tr ng-repeat="(key, value) in rowTitlesValues"
Is how my HTML fragment looks like, when I switch rowTitlesValues back to object works again, what am I doing wrong, and how does one keep insertion order or how do I sort object so it's keys are in custom order?
From Angular reference on ng-repeat (link):
Iterating over object properties
It is possible to get ngRepeat to iterate over the properties of an object using the following syntax:
<div ng-repeat="(key, value) in myObj"> ... </div>
You need to be aware that the JavaScript specification does not define the order of keys returned for an object. (To mitigate this in Angular 1.3 the ngRepeat directive used to sort the keys alphabetically.)
Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser when running for key in myObj. It seems that browsers generally follow the strategy of providing keys in the order in which they were defined, [...]
If this is not desired, the recommended workaround is to convert your object into an array that is sorted into the order that you prefer before providing it to ngRepeat. You could do this with a filter such as toArrayFilter or implement a $watch on the object yourself.
Additionally, I do not think Angular 1.x knows how to iterate over a Map. I believe this line in the code proves it:
collectionKeys = [];
for (var itemKey in collection) { // iterates your object using `in`, not `of` or `Map.forEach()`
...
}
// ng-repeat then iterates the collectionKeys to create the DOM
So you will probably need to act as Angular docs suggest:
[...] convert your object into an array that is sorted into the order that you prefer before providing it to ngRepeat. You could do this with a filter such as toArrayFilter or implement a $watch on the object yourself.
Related
When rendering a list of items, React uses the index of each item as a default key, if none is supplied.
return <div>
{this.props.shows.map(show => <ShowComp title = {show.title}/>)}
</div>;
But why doesn't React use the JS object reference of each item instead? Seems to me like a much safer option, as it would not cause re-rendering of any of the items if the list order changes (as opposed to the index approach).
I'm relatively new to React, so I'm sure there's an underlying reason.
In Angular, ngFor (which renders a list of elements, similar to mapping object to React elements), it also has a trackBy configuration option (which is the equivalent of key in React). However, if it's not supplied, it uses the object references as an identifier, which seems more natural.
The reason why it's not using the reference of the object by default is all React's developpers choice.
Keep in mind it doesn't have to be unique across all the items, it has to be unique across the siblings of each item.
As shown here : https://reactjs.org/docs/reconciliation.html#keys
You could definitely use a not so unique key that's only unique across siblings.
Also, is using the reference of the object faster than most small integer found in unique ids ?
I’m learning javascript and trying to write code that sorts a list, removing elements if they meet certain criteria.
I found this snippet that seems promising but don't have a clue how it works so I can adapt it to my needs:
list = document.getElementById("raffles-list").children; // Get a list of all open raffles on page
list = [].filter.call(list, function(j) {
if (j.getAttribute("style") === "") {
return true;
} else {
return false;
}
});
Can you guys help me learn by explaining what this code block does?
It's getting all the children of the "raffles-list" element, then returning a filtered list of those that contain an empty "style" attribute.
The first line is pretty self-evident - it just retrieves the children from the element with id "raffles-list".
The second line is a little more complicated; it's taking advantage of two things: that [], which is an empty array, is really just an object with various methods/properties on it, and that the logic on the right hand side of the equals sign needs to be evaluated before "list" gets the new value.
Uses a blank array in order to call the "filter" method
Tells the filter to use list as the array to filter, and uses function(j) to do the filtering, where j is the item in the list being tested
If the item has a style attribute that is empty, i.e. has no style applied, it returns true.
Edit:
As per OP comment, [].filter is a prototype, so essentially an object which has various properties just like everything else. In this case filter is a method - see here. Normally you just specify an anonymous function/method that does the testing, however the author here has used the .call in order to specify an arbitrary object to do the testing on. It appears this is already built into the standard filter method, so I don't know why they did it this way.
Array like objects are some of javascript objects which are similar to arrays but with differences for example they don't implement array prototypes. If you want to achieve benefits of array over them (for example like question filter children of an element )you can do it this way:
Array.prototype.functionName.call(arrayLikeObject, [arg1, [arg2 ...]]);
Here in question array like is html element collection; and it takes items without any styling.
list is assigned a collection of elements that are children of the raffles-list element
list is then reassigned by filtering its elements as follows
an empty array is filtered by calling it with the parameter list and a callback function. The formal parameters for call are this (which is the list) and optionally further objects (in this case a callback function)
The callback function receives a formal parameter j and is called for each element
If the element's value for the style attribute is empty the element is retained in the array. Otherwise it is discarded.
At the end list should contain all elements that don't have a value for its style attribute
I have an ng-repeat set up like so:
ng-repeat="article in main[main.mode].primary | orderBy: main[main.mode].primary.filter.order
track by article.url"
main[main.mode].primary is an array and ….filter.order is a string.
According to this blog post
Behind the scenes ngRepeat adds a $$hashKey property to each task to keep track of it. If you replace the original tasks with new tasks objects from the server, even if those are in fact totally identical to your original tasks, they won’t have the $$hashKey property and so ngRepeat won’t know they represent the same elements.
Regenerating the list is a very common task and the app is hanging for over a second, hence my interest in track by. According to the many questions and docs I've looked at, I've used the correct syntax to both order and track an array. From the docs:
item in items | filter:searchText track by item.id is a pattern that might be used to apply a filter to items in conjunction with a tracking expression.
Why isn't track by being implemented? I'm running angular 1.3.11.
Edit
It doesn't even work if I remove the orderBy argument
ng-repeat="article in main[main.mode].primary track by article.url"
according to the Angular Documentation orderBy only works on arrays so if you are iterating over an object you are not going to be able to use it unless you convert your object into an array
https://docs.angularjs.org/api/ng/filter/orderBy
there are other ways you can handle this either implementing your own filter or just by transforming your object into an array of objects with key value properties. something like
var narr=[]
angular.forEach(object,function(k,v){
narr.push({key:v,value:v})
})
and now narr is an array ready to be sorted by either key or value using orderBy
I am getting a model deferred object with a structure like this:
How can I find out how many objects are present inside this object (in this case, three). If I use Object.keys(myObject).length, it includes the object observer and other data also like _computeBindings,_bindings etc. I have even tried to use hasOwnProperty while calculating the length but its not giving me desired result.
One way I can figure out is to iterate over the index and get the last index value like this:
can.each(myObject,function(myObject,index){
// Get the last index value and put it into some variable
});
Is there an API for this?
can.Map has a keys function that will give you an Array of the keys in your Map and from that you can get how many Objects by checking that Array's length.
Using a can.List as your data structure would also work. The keys in your data are numeric and you need to check the length, all things that can.List is built for.
Try using myObject.attr('length')
The model _data attribute contains a copy of just the model without the bindings. The easiest way to do this is to use:
Object._data.length
Would like to maintain a map/hash of DOM objects. Can they serve as key objects? If not, what are the alternatives, please? If there are better ways - kindly enlist them as well.
You can put anything as the key, but before actual use it is always converted to string, and that string is used as a key.
So, if you look at what domObject.toString() produces, you see it is not a good candidate. If all of your dom objects have an id, you could use that id.
If not, and you still desperately need a key based on DOM object, you probably could do with using, for example, _counter attribute with automatic counter in background putting new unique value in a DOM object if _counter is not yet present.
window already maintains all DOM objects as properties. Instead of putting your own keys for each 'DOM object' try to use window or document object and methods that uses index based on the layout of DOM tree.
No, because object keys are strings.
You'd have to "serialise" your objects by id or something, then perform a lookup later. Probably not worth it, depending on what your actual goal is here.
No, but you can set an attribute on the DOM element that contains a number, which you would have as the index in a numerically-indexed array.
Easiest is to set a data-attribute on the element instead.
Not exact. But I think you want something like below. You can do with jquery,
The .serializeArray() method creates a JavaScript array of objects, ready to be encoded as a JSON string. It operates on a jQuery object representing a set of form elements. The form elements can be of several types
Refer below link :
http://api.jquery.com/serializeArray/