I have a ngRepeat block that iterates over an array of objects that draws row accordingly.
One of the properties of the object is a string that requires some transformation before displayed.
Performancewise, is it right to run the function everytime Angular runs its loop?
<div ng-repeat="a in arr">{{ strTransform(a.name) }}</div>
Yes, it is OK, performance-wise and everything, unless:
your transformation function itself is way too expensive, in which case you're doomed, or:
you got a humongous amount of elements to process, in which case you're doomed with the rendering time anyway.
--
As a side note, I'd like to add that you might wanna use an Angular filter (link) for these kinds of operations :)
Related
React documentation seems to be very insistent on the idea that in almost every situation, deriving state from props is a bad idea, an anti-pattern, verbose, likely to cause bugs, hard to understand, and all-around probably going to place a curse on one's lineage for a thousand years.
My use case isn't that weird, so I'm probably doing something wrong, but the suggested patterns for not needing getDerivedStateFromProps() (i.e. making Your object fully controlled or fully uncontrolled) don't seem like good solutions.
The situation: I have a Table component, that takes in an array rows as a prop. Table is used in many different places in my app. I want the Table to be able to handle row-sorting. It is obviously a bad idea to to make whichever parent component controls Table to have to control the sorting*, so fully controlled is out. Making Table fully uncontrolled with a key, also seems like it doesn't make a lot of sense unless the key is the row-data itself-- but my understanding is that key is meant to be simple data (like an id), and actually having to compare all of the rows, which are typically fairly complicated objects, would be pretty inefficient**. Using memoize-one is also not an option as I am working in a closed system and can't import any new libraries.
My current solution: Table has a state variable sortedRows which is updated either whenever sort() is called or whenever props.rows is updated (via getDerivedStateFromProps), by:
Making a shallow copy of props.rows,
in-place sorting that copy and
updating state.sortedRows on that value.
As I see it, there is still only one source of truth here (which is from props), and the state is always just storing a sorted version of that truth (but always dependent on and in sync with it).
Is this solution bad? If so why? What would be a better way to implement this?
Thanks!
Note: I didn't include my code because I am massively simplifying the situation in this prompt-- in reality Table element already exists, and is pretty complicated.
Note 2: I going to ask if I'd run into issues once I want to be able to modify elements in the tables, but I think I'm actually ok, since Table doesn't manage its elements, just arrange and display them, and the buttons for adding and removing elements from a table are not contained within Table, so all that processing is happening at the level of the parent's logic as passed down as part of props.rows
*Having something like <Table rows={sort(rowsFromParent)}/>every time I call Table is repetitive and error-prone, and since clicking on a table header determines sorting column, we'd actually have to have the parent element passing down an onClick() function in every case, which quickly and unnecessarily ramps up complexity).
**There is also a secondary problem to do with rebuilding an element. The table has an infinite scroll, such that when You reach a certain element more rows are loaded in. Using key will destroy the Table component and create a new one, scrolling the user to the top of the new table (which could potentially have many thousands of rows). Something also feels wrong about having to set key in each use of Table, even though resetting based on changes to props.rows seems like it should be intrinsic to how Table works, rather than something that has to be configured each time.
Edit: I have React 15.4, which is before getDerivedStateFromProps was added and using a later version is not an option, so I guess even if I happened to find a valid use case for getDerivedStateFromProps, an alternative would be nice...
The question is simple but for sure i believe it provides added value to an application development.
In terms of performance is it better to use:
ng-repeat="r in roads", ng-hide="r.distance > 1000"
OR is it better to push items in an array in the controller, like this:
for (var i in $scope.roads) {
var road = $scope.roads[i];
if (road.distance <= 1000) $scope.roadsToShow.push(road);
}
and then use, just the ng-repeat like so?
ng-repeat="r in roadsToShow"
Which is considered best practice in terms of better performance? Imagine that the objects in the arrays are more than 1000.
Filtering the array will be significantly better for several reasons.
The most important one is that ng-hide requires an internal watch be created and watches are expensive and can cause performance bottlenecks
Secondly there will be less dom nodes to render
There are numerous ways to do the filtering in angular also.
Do not use ng-hide, ng-show ng-if etc as filtering tools in ng-repeat
It is better to filter the items of the array in the controller or better on the server instead of hiding them after having rendered them. If you filter the array before displaying it the browser don't need to render the DOM associated to the item and then spending time to hiding it. Keep in mind that using ng-hide applies the CSS class display: none to the element, so the node exists but is not visible.
I am using Angular Meteor and I have a controller that subscribes to a publish-composite publish which returns two cursors. What I am trying to do is to ng-repeat on one cursor and get value from the second cursor based on the value of the first one. Like this:
{{getName(a.id)}}
where a is one object of the first cursor, and in the controller I have $scope.getName(id) function that returns name from the second cursor, like this:
name = second.find({ID: id}).fetch()[0].name
it worked but the problem is the getName function gets hit for unnecessary number of times. Is there a better way to get data from the second cursor based on ng-repeat object of the first cursor? Is nested ng-repeat the way to do? How can I do it?
Thanks.
It seems as if you are focused on the performance of the ng-repeat. Glad you feel this way! From what I remember, the ng-repeat has been a focus of optimization across many 3rd party libraries and discussions.
In your case, my first attempt would be to bind the value inside the ng-repeat only once. You can do this using the :: syntax on the expression.
For example, this would call the expression once.
<ul ng-repeat="a in items">
<li>{{::getName(a.id)}}</li>
</ul>
At the end of your question you mentioned a nested repeat but your question only mentions a single use of it. Am I missing something?
Disclaimer: I've never used Angular Meteor (or even standalone Meteor) so there could very well be a better way do solve your problem.
via: https://docs.angularjs.org/guide/expression
I have a problem where it looks like I'm going to need to use a Two step view.
The problem is basically that it appears I won't be able to use translate in the view in the way that I get the text as I want. I can solve this by using the translate service in my controller and then rendering the text into a view object there.
I'd rather not iterate over the list multiple times. Is there a way I can use an iterator (some way of saying next() in an ng-repeat statement? so that each time ng-repeat gets the next object, I can transform it then?
<md-list-item ng-repeat="artist in nextArtist() track by artist.name">
I have a big object lined in $rootScope (say > 100 objects and each having hierarchy of objects/array again), I want to $watch entire $rootScope with deepWatching(i.e. turning 3rd parameter of $watch to TRUE).
But the problem here is, $watch returns 2 objects (i.e. one Old RootScope and Modified RootScope). Then I have to do a process of checking what attribute of object changed in $rootScope and its hierarchy to PUSH it into stack.
Do we have an easy way out to get the exact attribute changed while watching a $scope?
$scope.$watch($rootScope, function(oldObj, newObj){
//all I want here is exactly what attribute changed, NOT entire objects!
}, true);
Alternatively, I could add watch on each attribute of the Object but it appears to be extremely expensive.
What is the best way to achieve undo/redo in angular js?
Note :-
angular-history doesnt suit my need because I want to watch all attributes of object, which may also contain other objects and array.
I'm certain watching entire $rootScope is not a good idea either, but I have aimed to build an UI which has several grids, drag n drop, might contain form, elements can be deleted. So I want to build an overall solution to stack the changes and undo it on CTRL + Z. Imagine replicating desktop version of Photoshop.
Undo/redo is based on the command pattern. And yes, there will be a lot of watches; such a rich functionality does not come cheap.
Just for the fun of it, here is a simple (but quite usable and extensible) implementation: http://jsfiddle.net/sYc4e/1/
A command is an interface for objects that know how to apply and rollback a change:
function XxxCommand() {
// implementation specific
}
Command.prototype.execute = function() {
// implementation specific
};
Command.prototype.rollback = function() {
// implementation specific
};
Usage: You decorate the <input>s with a directive:
<input name="name" undoable ng-model="data.name" />
And wrap them with an element (e.g. the <form>) with the undo-support directive:
<form undo-support>
The link function of undoable listens for a change in the <input> and registers a command with the undoableSupport. The controller of undoableSupport keeps track of the command list.
There's also an undo/redo library called Angular-Chronicle. For myself at least, it was a better option than angular-history.
The library angular-history provides undo/redo.
Currently not maintained. Most recent fork seems to be https://github.com/domoritz/angular-history.
instead of watching the whole $rootScope or for that matter any one object that contains a lot of items which in turn contain a lot of items requiring you to iterate through that nested array on every digest, I would use an array(using it as a queue) of changes that are applied to the original data model and a variable that points to a current location in that queue.
I would put that array and that variable in a service and then change that index whenever undo/redo happens. You can watch that variable from everywhere that you need to respond to these changes, like directives
I think the LazyJsonUndoRedo is what you're looking for.
https://github.com/azazdeaz/LazyJsonUndoRedo
From the readme:
A 'drop in' history handler with automatic undo/redo functionality for nested javascript objects, using ES6 Object.observe() or Polymer shim.
http://dailyjs.com/2014/07/18/lazy-json-undo/