When populating a drop down list with Backbone from a collection, how would I go about not adding duplicate entries, e.g. entries with the same (in this case) organisation name?
Currently what I have is this, which populates a drop down list:
[[ _.each(facilities.toJSON(), function(item) { ]]
<option value="{{ item.ID }}">{{ item.OrganisationName }}</option>
[[ }); ]]
You could implement a helper method on your collection:
var Facilities = Backbone.Collection.extend({
getUniqueByProperty: function(propertyName) {
return _.unique(this.toJSON(), function(item) {
return item[propertyName];
});
}
});
Usage:
[[ _.each(facilities.getUniqueByProperty('OrganisationName'), function(item) { ]]
<option value="{{ item.ID }}">{{ item.OrganisationName }}</option>
[[ }); ]]
/code sample not tested
Related
So I got a project which is using AngularJS with UI-Router, I iterate through a json which has a property called "state" which is what I want to use as a filter, however, I will be using a "selector" where I can pick "All" or a specific one.
I'm new to AngularJS So not sure exactly what is not working, this is the code I have so far:
function filterState (installment){
switch(selectedValue) {
case 1:
if(installment.state === 'PAID'){
return installment;
}
break;
case 2:
if(installment.state === 'LATE'){
return installment;
}
break;
case 3:
if(installment.state === 'PENDING'){
return installment;
}
break;
default:
return installment;
}
The filter however is not working as it should
Here is how I'm calling it:
<div class="row" ng-repeat="installment in vm.clients.installments | filter: filterState">
Not sure exactly what is the error, when I filter by a value manually like filter: {state:'PAID'}
It works
If you need to filter with a select option then you can do something like this:
<select name="select" id="select" ng-model="clients.status">
<option value="PAID">PAID</option>
<option value="LATE">LATE</option>
<option value="PENDING">PENDING</option>
<option value="ALL">ALL</option>
</select>
<div class="row" ng-repeat="installment in clients.installments | filter: filterState">
{{installment.id}}
</div>
And in controller the function to filter:
$scope.filterState = function(installment) {
if ($scope.clients.status === 'ALL') return true;
return $scope.clients.status === installment.status;
};
When option ALL is selected, it shows all the items of the list
Check a working demo here: DEMO
Apparently I needed to return a boolean value instead of the object, I did try that before, but my other issue was that I was calling the function directly instead of doing vm.function (once passed to the context), after doing that it worked.
Filter function returns an iterator function. like callback. Please check below example.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.criteria = { name: 'Bob'};
$scope.criteriaMatch = function( criteria ) {
return function( item ) {
return item.name === criteria.name;
};
};
$scope.items =[
{ name: 'Bob'},
{ name: 'Alice'}
];
});
<div ng-repeat="item in items | filter:criteriaMatch(criteria)">
{{ item }}
</div>
http://plnkr.co/edit/vtNjEgmpItqxX5fdwtPi?p=preview
Credit: Anonymous
I have query in my repository, that returns array result:
$result = $qb
->select('partial u.{id, username, email, lastLogin}', 'partial groups.{id}')
->leftJoin('u.groups', 'groups')
->getQuery()
->getArrayResult();
When I requests this query on my AngularJS app, I getting next result:
[
{"id":1,
"username":"Sergio Ivanuzzo",
"email":"my_email#domain.com",
"lastLogin":null,
"groups":[{"id":1}]
}
]
Because of groups contains array of objects, I can't parse them in my editable directive (checkboxes not checked):
<span
data-pk="{{ user.id }}"
editable-checklist="user.groups"
e-ng-options="g.id as g.name for g in groups"
e-form="rowform">
{{ User.showGroups(user) }}
</span>
When groups attribute contains something like [1,2,3] directive is working (checkboxes are checked normally).
So, for fixing this I'm parsing each User object from response:
angular.forEach(response.data, function(user) {
var groups = [];
angular.forEach(user.groups, function(group) {
groups.push(group.id);
});
user.groups = groups;
});
$scope.users = response.data;
I feel, that I can avoid this workaround, If I could return groups for each user as sequence of numbers. How can I do this? Maybe better way exists?
If you need extra data, please, let me know! Thanks a lot for any help
You can use a filter to preserve your original data like
$scope.toArray = function(groupsAsObjects) {
var groups = [];
angular.forEach(groupsAsObjects, function(group) {
groups.push(group.id);
});
return groups;
};
And
<span
data-pk="{{ user.id }}"
editable-checklist="user.groups | toArray"
e-ng-options="g.id as g.name for g in groups"
e-form="rowform">
{{ User.showGroups(user) }}
</span>
Or remap your full array of objects as arrays like this :
$scope.toArray = function(obj, addKey) {
if (!obj)
return obj;
if (addKey === false) {
return Object.keys(obj).map(function(key) {
return obj[key];
});
} else {
return Object.keys(obj).map(function(key) {
return Object.defineProperty(obj[key], '$key', {
enumerable: false,
configurable: true,
value: key
});
});
}
};
I've tried most of the SO answers for identifying unique values in angular.js ( i am a novice) but my problem is trying to get these into a select form and for that to have a filter on the data in a table.
essentially i have some data, I want to display it in a table and in the table header have a select dropdown of unique values in that column of data and be able to filter the table displayed by values selected.
I'm trying to use
app.filter('unique', function () {
return function ( collection, keyname) {
var output = [],
keys = []
found = [];
if (!keyname) {
angular.forEach(collection, function (row) {
var is_found = false;
angular.forEach(found, function (foundRow) {
if (foundRow == row) {
is_found = true;
}
});
if (is_found) { return; }
found.push(row);
output.push(row);
});
}
else {
angular.forEach(collection, function (row) {
var item = row[keyname];
if (item === null || item === undefined) return;
if (keys.indexOf(item) === -1) {
keys.push(item);
output.push(row);
}
});
}
return output;
};
});
and my html looks like this
<th> Number:
<br/>
<select ng-model="search.number"
ng-options="row.numberfor row in data | unique:'number'">
<option value=""> </option>
</select>
</th>
and then the table data itself
</tr>
</thead>
<tbody>
<tr ng-repeat="r in data | filter:{ number: search.number, }">
<td> {{r.number}}</td>
</tr>
</tbody>
</table>
The output generates this, but the value isn't set correctly so filtering returns nothing (as 0,1,2,3.. have not matching rows of data).
<select ng-model="search.number"
ng-options="row.numberfor row in data | unique:'number'"
class="ng-pristine ng-valid">
<option value="" class=""> </option>
<option value="0">1023 456789</option>
<option value="1">1024 456789</option>
<option value="2">1025 456789</option>
<option value="3">1023 111999</option>
<option value="4">1024 111999</option>
</select>
I've also tried this unique function
/*
app.filter('unique', function() {
return function(input, key) {
var unique = {};
var uniqueList = [];
for(var i = 0; i < input.length; i++){
if(typeof unique[input[i][key]] == "undefined"){
unique[input[i][key]] = "";
uniqueList.push(input[i][key]);
}
}
return uniqueList;
};
}); */
but no joy. i had to add [key] to this line uniqueList.push(input[i][key]); just to get the values displayed in the drop down, but I can't seem to control the values of the options in that drop down.
I have no errors in my console.
I have 10 columns/fields to filter on, but I've just included one example here.
Can someone help point me in the right direction. thanks
edit:
I see this directive might be useful, but when the map key->value are the same, is there a quicker/easier way?
app.directive('mySelect', [function () {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<select ng-options="key as value for (key, value) in myMap" ng-transclude></select>',
link: function postLink(scope, element) {
scope.myMap = {"1":"1","2":"2","3":"3"};
// e.g. hashmap from server
}
};
turns out this works
<select ng-model="search.<?php echo $column; ?>"
ng-options="v for (k, v) in data
| orderBy:'<?php echo $column;?>'
| unique:'<?php echo $column;?>' ">
<option value="">select</option>
</select>
stuck within a foreach that looks at the each of columns in a CSV file.
i.e. the full excel style filtering with any csv passed in.
I use ng-repeat:
<option ng-selected="key == formData.city" ng-repeat="(key, value) in data.cities | orderBy:value" value="{{key}}">{{value}}</option>
data.cities is array.
Also I have method that gets array of cities from AJAX response and sets it to exists array $scope.data.cities:
request.success(function (data) {
var arr = []
angular.forEach(data.res, function(item) {
arr[item.id] = item.name;
});
$scope.data.cities = arr;
});
Why after response I get error: [ngRepeat:dupes]?
You have to use track by $index with your ng-repeat to avoid duplicates:
ng-repeat="(key, value) in data.cities track by $index | orderBy:value"
https://docs.angularjs.org/error/ngRepeat/dupes
Update:
You memory leak might be a reason of using array:
var arr = [];
For example, if your cities.id looks like 1001 this will produce an array with 1000 empty items and one with your city.
In your situation I would recommend to use an Object instead of Array:
request.success(function (data) {
var obj = {};
angular.forEach(data.res, function(item) {
obj[item.id] = item.name;
});
$scope.data.cities = obj;
});
Also, you can replace ng-repeat with ng-options here:
<select ng-model="formData.city" ng-options="key as value for (key, value) in data.cities">
I am using this code in my controller:
$scope.$watch('option.selectedPageType', function () {
if ($scope.isNumber($scope.option.selectedPageType)) {
localStorageService.add('selectedPageType', $scope.option.selectedPageType);
}
})
getPageTypes: function ($scope) {
$scope.option.pageTypes = [
{ id: 0, type: 'Edit Basic' },
{ id: 1, type: 'Edit Standard' },
{ id: 2, type: 'Report' }
];
$scope.option.selectedPageType = parseInt(localStorageService.get('selectedPageType'));
},
and in my HTML:
<select data-ng-model="option.selectedPageType"
data-ng-options="item.id as item.type for item in option.pageTypes">
<option style="display: none" value="">Select Page Type</option>
</select>
Instead of using the "Select Page Type" option. How can I make it so my code defaults to the value in local storage or if there is nothing there then to one of the values I have in my option.pageTypes list ?
Have your localStorageService return null if there is nothing stored. If it does exist, have the service return the integer
Then in controller:
/* assume want first item in array */
$scope.option.selectedPageType = localStorageService.get('selectedPageType') || $scope.option.pageTypes[0].id
Try using ng-init on the <select ...>:
<select data-ng-model="option.selectedPageType"
data-ng-options="item.id as item.type for item in option.pageTypes"
data-ng-init="option.selectedPageType=DEFAULT_VALUE">
See this fiddle: http://jsfiddle.net/CaeUs/5/