Angular 2 function expression in *ngFor - javascript

I need to use a function expression in *ngFor like this,
<select>
<option *ngFor="let item of getItems(someValue)">
..........
</option>
</select>
Is there any issue in using a function like getItems(someValue) where I get the items based on the 'someValue'.
Is this approach ok or should I use some other way?

Its recommended that you dont use functions directly when binding to the UI, as these will be run every time the change detection lifecyle runs, possibly leading to poor performance.

*ngFor should be used only for binding with an array declared in your component. If this array changes over time, that's ok because Angular knowns when to redraw the view based on your variables.
You can do this in your component:
public items: YourObject[];
You can assign the values in the constructor, or any other place:
constructor(){
this.items = this.getItems(someValue);
}
Then just use it in the *ngFor like this: let item of items

Related

How to use variable inside variable in angular template?

I am new to angular , can someone tell me if I can use variable inside variable in angular.
Explaination:
I am creating one dropdown input component where it will make api call to get data.
There is an #Input() selector:string = "" which will tell what to select from data
Inside template it will run *ngFor loop, then inside html I want to display as kind of like that:
<option *ngFor="let item of data" [value]="item.id">
{{ item.{{selector}} }}
</option>
In other module it will be used as:
In one module <app-input [selector]="'name'"></app-input>
Another one. <app-input [selector]="'id'"></app-input>
How Can I use selector inside this any way?
{{ item[selector] }}
use the bracket syntax for accessing a property with a variable key.

AngularJS ng-init not initializing variable globally

I am using ng-repeat of angularjs directive to load the array which have JSON value store in it. and value has subarray also.
<div ng-repeat="data in MENULIST" > //MENULIST have array(Data)
after checking some conditions like (if:condition).
<div ng-if="(data.SubMenu.length >0)" ng-init = "MENULIST = data.SubMenu"></div>
but that assignment or initialization is not been done globally to MENULIST it limited to this div Only.
ng-repeat stop after printing two main array elements.
not printing Sub Element of Array Element.
actually, I am trying to make and tree structure in the sidebar that has menu and sub menus also.
Besides two-way binding should work for you I believe calling some function is more straightforward way(especially since you can create this function in scope of particular controller - so it would be much easier to get the point)
<div ng-if="(data.SubMenu.length >0)"
ng-init = "someController.setMenuList(data.SubMenu)">
</div>
Another "angular-way" is adding explicit watcher to data.Submenu.length in component's JS code
$scope.$watch('data.Submenu.length', function (value, oldValue) {
if (!value && oldValue) {
// do your init
}
});

Angular State Dropdown Bound to Country Select

I am trying to have a contextual state dropdown menu that is bound to the country so that only the relevant states display.
I have looked at these two answers for a solution to my implementation.
Angularjs trigger country state dependency
angularjs dependant dropdown option value
But I cannot get them to work and am missing something.
My preferred solution would use some existing ng filter, but I understand that only works on arrays and not objects
<select ng-model="user.state" ng-options="state.name for state in states track by state.id | filter:state.countryid = user.country.id">
I tried converting the object to an array, but that did not seem to work.
I could create a custom filter, but I am hoping to avoid that.
<select ng-model="user.state" ng-options="state.name for state in states track by state.id | customStateFilter:user.country.id">
It seems like there should be some way to get ng-options to work without modifying the data.
Is there an existing Angular filter that works on objects or a way to do conditional logic to filter out the objects dynamically?
You have a few issues here (in addition to a mismatch of state.countryid and country.id):
First, track by comes after the filter (or, in other words, filter comes right after the array, since it filters the array).
Second, you are right - the built-in filter filter only works on arrays, not objects. For objects, you'd need a custom filter.
And lastly, filter filter doesn't accept an expression to evaluate (filter:state.countryid = user.country.id, not to mention that this "expression" that you tried to provide doesn't compare ===, but assigns =). filter accepts as a parameter either a string - to match any property against, an Object specifying which property to match against which value, or a predicate function.
In your case, an object is what you need.
To put this thing together you get:
<select ng-model="selectedState"
ng-options="state.name for state in states | filter: {countryid: user.country.id}:true track by state.id">
<option value="">select state</option>
</select>

Pass parent scope value into ng-repeat loop in Angular

This should be an extremely simple question, but all of the workarounds I've found are complex. I'm looping through an array of objects in using ng-repeat in a template as follows:
<div class="row-fluid" ng-repeat="message in messages.current|filter:'draft'">
{{ message.subject }} ... {{ campaign.name }} ...
</div>
Since the ng-repeat creates a new scope, the 'campaign' object from the controller doesn't seem to be accessable. Is there any way (aside from adding the campaign object to every item in my array) of getting that value?
Thanks in advance.
You can access the parent scope by using $parent
<div class="row-fluid" ng-repeat="message in messages.current|filter:'draft'">
{{ message.subject }} ... {{ $parent.campaign.name }} ...
</div>
This is a way that works that doesn't use $parent. It searches upwards through the nested scopes to find the object you're using, however many scopes it has to go through.
In the scope that contains the list, you can define an object with the list as a property, like this:
$scope.obj = {};
$scope.obj.items = ['item1','item2','item3'];
Then have the ng-repeat look like this:
<div ng-repeat="item in obj.items | filter:'item3' track by $index">
{{obj.items[ obj.items.indexOf(item) ]}}
</div>
(you need to use obj.items[ obj.items.indexOf(item) ] rather than obj.items[ $index ] because $index is the index of the filtered array, not the original)
The reason this works is because while obj doesn't exist in the current scope, as you attempt to access its property, Angular will look above the current scope rather than give you an error (if you just tried {{obj}} it would be undefined, and Angular would be happy with giving you nothing instead of looking through higher scopes). This is a helpful link about nested scopes: http://www.angularjshub.com/examples/basics/nestedcontrollers/
In my case I needed the track by $index, because I had an input with ng-model bound to an item in the array, and whenever the model updated, the input would blur because I think the HTML was being re-rendered. A consequence of using track by $index is that items in the array with identical values will be repeated. If you modify one of those other than the 1st one, weird things will happen. Maybe you can filter for uniqueness to avoid that.
I'm relatively new to AngularJS, so please comment if there is anything big I'm missing. But this works, so I'm using it at least.
Another method might be to pass parent scope as a scope variable to the directive i.e.
<my-directive
md-parent-scope="this"
ng-repeat="item in items"></my-directive>
It's a bit messy, but you have more control over what the parent actually is and can pass anything in.

Iterating through models for a select field with Rivet.js & Coffeescript

I'm attempting to populate a select field with options using bootstrapped data. I'm encountering an issue when binding my array of models to the jQuery select object...
The HTML
<select data-each-project="projects" id="project-selection">
<option data-value="project:description"></option>
</select>
The Binding
project_array = new Array()
_.each projects, (project) ->
projects_array.push project
rivets.bind #el.select, projects:projects_array
The Result
I receive an error indicating that the object has no .on method -> which it doesn't because it is an array of models not a model it self...
How should this really be done? Thanks!
When you subscribe to an iteration binding rivets does two things:
Subscribes to the entire array so if it changes it will rerun the
iteration
Subscribe to all children of the array that need binding
Rivets isn't subscribing to your children because you are not using any bindings that require it.
project:description = non-subscribe binding
project.description = subscribe binding
If you don't want to subscribe to array changes (I think that's what you're asking for) you can do data-each-project=":projects"

Categories