Angular dynamic model naming? - angularjs

i'm learning angular, so please be gentle ;)
I have a table that is populated with some data. And i would like to add filtering (not angular filter, but data filter) on each column.
The idea for me is to add a text box at the top of each column in the header. Then use those textbox values to create the Filters array in my service when it called the api to get the data.
I currently have:
<tr>
<th ng-repeat="column in report.Columns" ng-show="column.IsVisible">
<span class="sort" ng-click="updateSortOrder($index)" ng-class="{'sort-asc': predicate == $index && !reverse, 'sort-desc':predicate == $index && reverse}">{{ column.DisplayName }}</span>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-filter fa-fw"></i></span>
<input class="form-control" type="text" placeholder="Search" ng-model="">
</div>
</th>
</tr>
what i'm stuck on, is how to assign the text boxes to the ng-model, naming them dynamically based on the column that they stand in.
I thought about using ng-model="column.ColumnName" - but wont that bind the text boxes to the report.Columns.ColumnName ? i dont want to edit that, i want to create a new var on the scope for each one.
Something like $scope.Filters.-ColumnName-.
And then i would like to loop through each ColumnName on $scope.Filters and use it's value in my filters array on my service call.
I hope this is making sense. If I'm heading down the wrong route to achieve this, please feel free to point me in the right direction, as i said, i've just started learning Angular.
Thanks in advance

This is not angular related specifically it is more of a javascript issue.
For variable property names you use [] object notation
<input ng-model="filters[column]"
In controller :
$scope.filters ={}
If properties aren't already created in the scope object, ng-model will create them automatically when there is any user input

Related

What magic does ngModel use that modifying the scope directly does not?

Learning angularjs at the moment, and I am confused as to how I can accomplish a task because I don't fully understand what ngModel is doing.
If I have a directive with two scope variables:
// An array of all my objects
$scope.allMyObjects
// The currently selected object from the array
$scope.selectedObject
and in the html
<span>{{ selectedObject.name }}</span>
<select id="select"
ng-model="selectedObject"
ng-options="object in allMyObjects">
</select>
This all works perfectly, when I select an object from the select, it updates the selectedObject on the scope and so the name of the currently selected object is displayed.
However, I don't want a select box, instead I want a list of all my objects with an editable name field, with a select button that I can use to select the specified object, so I came up with the following:
<div ng-repeat="object in allMyObjects">
<input class="object-name"
ng-model="object.name">
<a ng-click="loadObject(object)">Load</a>
</div>
and the loadObject() function on the scope:
function loadObject(object) {
$scope.selectedObject = object;
}
However, this doesn't work. I had assumed this was basically what ngModel was doing behind the scenes but am obviously confused. Is anyone able to shed some light or offer a better solution to what I wish to achieve?
Please see here :http://jsbin.com/jocane/1/edit?html,js,output
use ng-model="object.name" instead "sc.name"
<div ng-repeat="object in allMyObjects">
<input class="object-name"
ng-model="object.name">
<a ng-click="loadObject(object)">Load</a>
</div>
After an hour of debugging it came down to an issue with the scope being isolated by the ng-repeat, the problem didn't show up in any of the simplified jsfiddle examples because they used pure JS and it was the way I was accessing the scope via typescript that caused the issue.
Thanks for the answers that helped me narrow it down to my difficulty understanding typescript and not my difficulty understanding directives.

dynamic ng-model inside ng-repeat

I am loading data from database in JSON Format, like this: ($scope.fees):
{"1_0":"2000","1_1":"1900","1_2":"1800","1_3":"1700","1_4":"1600","1_5":"1500","1_6":"1400","1_7":"1300","2_0":"4000","2_1":"3900","2_2":"0","2_3":"0","2_4":"0","2_5":"0","2_6":"0","2_7":"0"}
This needs to be displayed in a table (like grid), in which rows and columns are not fixed. This code works for me now:
<tbody data-ng-repeat="obj in courses"><!-- Courses JSON -->
<tr><th>{{obj.name}}</th></tr>
<tr data-ng-repeat="bat in obj.batches"><!-- Each course contains Batches -->
<td>{{bat.bname}}</td>
<td data-ng-repeat="obj in categories"><!-- Columns based on categories -->
<input type="text" name="{{bat.bid}}_{{obj.id}}" data-ng-model="fees.1_0" />
</td>
</tr>
data-ng-model="fees.1_0" should be actually as provided for the name attribute: data-ng-model="fees.{{bat.bid}}_{{obj.id}}" but this doesn't work. Is there any solution to get this working? Thanks in advance.
Edit: I can change the JSON format if there is a better solution to get this done. The current format is batch<underscore>category: fees
Try data-ng-model="fees[bat.bid + '_' + obj.id]"
Check this Demo. This shows how to attach model dynamically from JSON object.May this will help you.
Just like variable keys in javascript use [] in the ng-model as the as bracket value must be your object key

Need a callback after filtering the rows when using ng-repeat along with filter in angularjs

I am using angularjs, ng-repeat to fill the required data in the datagrid.
Something like this:
<input type="text" placeholder="Search" ng-model="query">
<tr ng-repeat="item in items | filter:query">
<td>{{item.someData}}</td>
<td>{{item.someOthrData}}</td>
</tr>
when I enter some query string to filter the rows in the datagrid, at the end when the rows are filtered I need a callback, to do some application specific stuff.
Kindly if anyone can suggests what will be the right way to do this.
Thanks.
Try to use $watch method of the scope which detects changes of the defined expression. For your case, you need to watch "items" like:
scope.$watch('items', function() {
console.log('Search key was entered');
});

Ng-model's attribute in a ng-repeat input checkbox gets always literal or give error

So i need to know the extras of a car than a user wants to include in his preferences.
I'm trying to create input checkboxes from an array obtained by an ajax request and generate the inputs by ng-repeat. The major objective is to know the checkboxes selected by the user. I'd like that my approach to be create an auxiliar array which contains the selected ones, but i don't know how to set a unique ng-model to every item in the ng-repeat iteration so i can know the list of selected items. I guess there is something left in my knowlege of angular. Here is what i have for now..
In the controller...
$http.get('/ajax/ajax_get_extras/'+$scope.car.version+'/false').success(function(data) {
$scope.extras = data;
});
$scope.addExtra = function(){ // ... manage the auxiliar array }
In the html ...
<div ng-controller="Controller">
<form novalidate class="simple-form">
<span ng-repeat="extra in extras">
<input type="checkbox" ng-model="extra.id" ng-change="addExtra()" name="extra_{{extra.id}}" >{{extra.name}} - <strong>{{extra.real_price | onlynumber | currency}}</strong>
</span>
</form>
</div>
And i'm stuck since the extra.id doesnt transform to the real extra.id and stays as a string "extra.id" >_<
I tried extra_{{extra.id}}, extra.id, {{extra.id}}, $index as posibles ng-model and none works.
In AngularJS 1.1.5 there is "track by" that you can use in ngRepeat.
So you can:
<input type="checkbox" ng-repeat="e in extra track by $index" ng-model="extra[$index]">
Here is a example: http://plnkr.co/edit/6lNo6R5EPsNGHUU6ufTE?p=preview

Referencing scope children in filters (AngularJS)

I'm an AngularJS newbie, and am putting together a pretty basic proof-of-concept for my boss. It's listings for car hire, with a results list in the main area of the view populated via some external JSON, and a filters panel down the side. You can see the Plunker I've created here:
http://plnkr.co/lNJNYagMC2rszbSOF95k
I've been able to successfully reference child objects/values in my ngRepeat:
<article data-ng-repeat="result in results | filter:search" class="result">
<h3>{{result.carType.name}}, {{result.carDetails.doors}} door, £{{result.price.value}} - {{ result.company.name }}</h3>
<ul class="result-features">
<li>{{result.carDetails.hireDuration}} day hire</li>
<li data-ng-show="result.carDetails.airCon">Air conditioning</li>
<li data-ng-show="result.carDetails.unlimitedMileage">Unlimited Mileage</li>
<li data-ng-show="result.carDetails.theftProtection">Theft Protection</li>
</ul>
</article>
...however, I've so far been unable to access the 2nd level child objects in my search filter. So, for example, where I'm filtering by 'car type' (see below), I'd like to be able to use 'search.carType.name' as my ngModel, to be as specific as possible - but this doesn't work, although just using 'search.carType' works fine. Can anyone advise on what I'm doing wrong?
<h4>Car type:</h4>
Compact <input type="checkbox" data-ng-model="search.carType" ng-true-value="Compact" ng-false-value="" /><br>
Intermediate <input type="checkbox" data-ng-model="search.carType" ng-true-value="Intermediate" ng-false-value="" /><br>
Premium <input type="checkbox" data-ng-model="search.carType" ng-true-value="Premium" ng-false-value="" /><br>
Your search object is being populated correctly, but filter isn't consuming it in the way you expect. Looking at the implementation of filter (https://github.com/angular/angular.js/blob/master/src/ng/filter/filter.js), it appears to only go one layer of child-properties deep when it is given an object as a filter definition.
Ajay's suggestion will work, but you would then need to chain additional filters to accomodate your other parameters. You could change both car type and company to specify x.name in the ng-model and then alter the filter to filter:search.carType.name|filter:search.company.name. If you were only going to have a small number of parameter types, I'd handle it this way.
On the other hand, the nice thing about your current approach is that it's transparent. There's no need to the filter call to be changed if the number of parameters changes elsewhere. If you might have a relatively large number of those, or if they were dynamic, I would take a more scalable approach. Write a filter FUNCTION that consumes the search object, and goes more than one level deep in comparing the children to the filtered data.
Here is a nice post by Anton Kropp on deep object filtering: FILTER ON DEEP OBJECT PROPERTIES IN ANGULARJS
The relevant code:
function initFilters(app){
app.filter('property', property);
}
function property(){
function parseString(input){
return input.split(".");
}
function getValue(element, propertyArray){
var value = element;
_.forEach(propertyArray, function(property){
value = value[property];
});
return value;
}
return function (array, propertyString, target){
var properties = parseString(propertyString);
return _.filter(array, function(item){
return getValue(item, properties) == target;
});
}
}
And the HTML
<ul>
only failed: <input type="checkbox"
ng-model="onlyFailed"
ng-init="onlyFailed=false"/>
<li ng-repeat="entry in data.entries | property:'test.status.pass':!onlyFailed">
<test-entry test="entry.test"></test-entry>
</li>
</ul>
And a JSFiddle here

Resources