Angularjs - showing element based on a presence of id in array - javascript

Does anyoen know how to check (in the View) for a presence of id in a given array?
Lets say I have an array like so:
var arr = [123, 456, 789];
and a data source like this:
var data = [
{id: 123, name: 'foo'},
{id: 456, name: 'bar'},
{id: 789, name: 'baz'}
];
Now in the view while iterating over the data array I would like to show/hide elements based on a presence of id in the arr like so:
<div ng-repeat="item in data">
<span ng-show="item.id in arr"></span>
</div>
The above code item.i in arr of course does not work for obvious reasons. Anyone know how to achieve that functionality? Not to mention the ng-show block should always kick-in whenever the arr array is altered.
Thanks in advance.

You can just create a method in your scope
function MyCtrl( $scope ) {
$scope.data = ...
$scope.enabled = ...
$scope.visible = function (id ) {
return $scope.enabled.indexOf(id) > -1
}
}
and
<span ng-show="visible(item.id)" ></span>

Related

I have a collection of items. Based on the two data points, I need to query that items

I have a collection of items. Based on the two data points, I need to filter out that items. As an example: I have a collection of action objects [{name: Detail}, {name: Spec}...] and I have two data points like I am category 'G' and in page 'A' would use only Detail action but I am category 'G' but in page 'B' only use Spec action and etc. What is the best OOP approach for this problem to scale to 100 of actions and base that on 10 of category and pages? I have tried to solved with Factory pattern but it did not work out.
The simplest solution is to create mapping of pages and allowed actions for this page.
Example:
const actions = [{name: 'Detail'}, {name: 'Spec'}];
const pages = [
{
name: 'A',
allowedActions: [{name: 'Detail'}]
},
{
name: 'B',
allowedActions: [{name: 'Spec'}]
}
]
const getAllowedActions = pageName => {
return pages.find(page => page.name == pageName).allowedActions;
}
console.log(getAllowedActions('A'));
Out:
[ { name: 'Detail' } ]

Angular changing dataset without $watch

I have an array of objects like this
UserList = [
{name:'user1',id:1,data:{}},
{name:'user4',id:4,data:{}},
{name:'user7',id:7,data:{}}
]
And html select like this
<select ng-model="data.selectedUser">
<option ng-repeat="item in data.items" value="{{item.id}}">{{item.name}}</option>
</select>
<p>{{data.userPhone}}</p>
Inside my controller I use
$scope.data = {};
$scope.data.selectedUser = 0;
$scope.data.items = UserListModel.items;
$scope.data.userPhone = UserListModel.items[$scope.data.selectedUser].phone;
Is there a way to update selected user phone on selectedUser change without using $watch and stuffing the "$scope.data.userPhone" inside it?
Imagine you have a data like this:
$scope.data = {};
//set the data
$scope.data= [{
id: 1,
name: "cyril",
phone: "1234567"
}, {
id: 2,
name: "josh",
phone: "1237"
}, {
id: 3,
name: "sim",
phone: "4567"
}];
//selected hold the object that is selected in the selectbox.
$scope.selected = $scope.data[0];
Your html will look like this below so now when you select the new user from the list it will be updated in the model selectedItem, the selectedItem has the phone number in it (so you dont need a watch to update phone number seperately as you doing).
<body ng-controller="MainCtrl">
<p>selected item is : {{selectedItem}}</p>
<p> name of selected item is : {{selectedItem.name}} </p>
<select ng-model="selectedItem" ng-options="item.name for item in items track by item.id"></select>
</body>
working example here
One possibility would be to have
$scope.data.userPhone = function () {
return UserListModel.items[$scope.data.selectedUser].phone;
}
This would mean though that you'd have to update any bindings to use data.userPhone() instead.
This might be worse than using a watch though, as the function would get called during every digest.
Without knowing how selectedUser gets updated it's difficult to suggest a best way as, with most things, it depends.

AngularJS dropdown not showing selected value

Am facing problem in displaying selected value in angular dropdown.
it works when i give like this
$scope.selectedItem = $scope.items[1];
not working, if i give directly that value
$scope.selectedItem = { name: 'two', age: 27 };
HTML:
<html ng-app="app">
<body>
<div ng-controller="Test">
<select ng-model="selectedItem" ng-options="item.name for item in items">
</select>
</div>
</body>
</html>
JS:
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.items = [{name: 'one', age: 30 },{ name: 'two', age: 27 },{ name: 'three', age: 50 }];
$scope.selectedItem = $scope.items[1];
});
CODEPEN:
http://codepen.io/anon/pen/zxXpmR
SOLUTION:
Thank you samir-das. I fixed as per your suggestion.
var choosen_value = { name: 'two', age: 27 };
angular.forEach($scope.items, function(item){
if(angular.equals(choosen_value, item)){
$scope.selectedItem = item;
}
});
As explained in the other answers, while the two objects may have the same properties and values, they are two different objects so angular doesn't consider them to be equal.
You can however use the track by expression in ng-options to specify a property which will decide equality:
ng-options="item.name for item in items track by item.name"
http://codepen.io/anon/pen/WbWMrp
Well, because
$scope.items[1] and { name: 'two', age: 27 } is totally different thing.
{ name: 'two', age: 27 } is a totally different object whereas $scope.items[1] is part of the object $scope.items
When you put something in the template using {{}}, angular add it in its watcher list.
SO when angular put it in the watch list, it was an object (i.e. { name: 'two', age: 27 } ) that is different than $scope.items.
selectedItem is attached with the object that you set in the controller. In summary while dirty checking, angular will checks selectedItem against { name: 'two', age: 27 } NOT against $scope.items
Hope you understand what I mean
This is not an Angular feature/issue, it is a consequence of how object equality works in Javascript. This article does a fairly good job in explaining what is going on in a pretty concise way and gives some examples. Check out the source of lodash's isEqual method (it will take you to the definition of baseIsEqualDeep eventually) to see how what you are trying to achieve can be done in pure JS.
In any case, I do not think there is an easy way to achieve this in Angular, you would have to re-write the way ng-options works and you probably do not want to go there...
In angular, Arrays and objects are passed by reference while strings, numbers and booleans are passed by value. So, angular interprets $scope.items[1] and { name: 'two', age: 27 } as two different objects. That's why your binding fails when you do $scope.selectedItem = { name: 'two', age: 27 }; directly and find it in '$scope.items'.

polymer bind data to div id

I have a polymer element in which I can declare an array and use it as below.
...
<template repeat="{{chapters as chapter}}">
<core-submenu id='{{chapter.id}}-core-submenu' label="{{chapter.label}}">
</core-submenu>
</template>
...
Polymer('app-element', {
chapters: [{id: one, label: one}, {id: two, label: two}],
...
somethingChanged : function(){
this.$[this.chapter.id + '-core-submenu']
}
...
}
It works as expected if I fill the chapters object as above.
I want to will this chapters from outside. I then do the following:
var app = document.querySelector('#app');
window.addEventListener('polymer-ready', function() {
app.chapters = [{id: one, label: one}, {id: two, label: two}];
});
If I do that, this.$[this.chapter.id + '-core-submenu'] is now null. I guess it happens because the this.$ is filled before the polymer-ready event is fired.
Does it make sense? Which would be the best practice to now access this element? I was hoping to still be able to access it through this.$.
Best
Nicolas
I would suggest to expose this property as polymer attribute and then access that from outside using setAttribute
window.addEventListener('polymer-ready', function() {
var app = document.querySelector('#app');
app.setAttribute('chapters',[{id: one, label: one}, {id: two, label: two}]);
});

How to use parameters within the filter in AngularJS?

I want to use parameter in filter, when I iterate some arrays with ng-repeat
Example:
HTML-Part:
<tr ng-repeat="user in users | filter:isActive">
JavaScript-part:
$scope.isActive = function(user) {
return user.active === "1";
};
But I want to be able to use filter like
<tr ng-repeat="user in users | filter:isStatus('4')">
But its not working. How can I do something like that?
UPDATE: I guess I didn't really look at the documentation well enough but you can definitely use the filter filter with this syntax (see this fiddle) to filter by a property on the objects:
<tr ng-repeat="user in users | filter:{status:4}">
Here's my original answer in case it helps someone:
Using the filter filter you won't be able to pass in a parameter but there are at least two things you can do.
1) Set the data you want to filter by in a scope variable and reference that in your filter function like this fiddle.
JavaScript:
$scope.status = 1;
$scope.users = [{name: 'first user', status: 1},
{name: 'second user', status: 2},
{name: 'third user', status: 3}];
$scope.isStatus = function(user){
return (user.status == $scope.status);
};
Html:
<li ng-repeat="user in users | filter:isStatus">
OR
2) Create a new filter that takes in a parameter like this fiddle.
JavaScript:
var myApp = angular.module('myApp', []);
myApp.filter('isStatus', function() {
return function(input, status) {
var out = [];
for (var i = 0; i < input.length; i++){
if(input[i].status == status)
out.push(input[i]);
}
return out;
};
});
Html:
<li ng-repeat="user in users | isStatus:3">
Note this filter assumes there is a status property in the objects in the array which might make it less reusable but this is just an example. You can read this for more info on creating filters.
This question is almost identical to Passing arguments to angularjs filters, to which I already gave an answer. But I'm gonna post one more answer here just so that people see it.
Actually there is another (maybe better solution) where you can use the angular's native 'filter' filter and still pass arguments to your custom filter.
Consider the following code:
<li ng-repeat="user in users | filter:byStatusId(3)">
<span>{{user.name}}</span>
<li>
To make this work you just define your filter as the following:
$scope.byStatusId = function(statusId) {
return function(user) {
return user.status.id == statusId;
}
}
This approach is more versatile because you can do comparisons on values that are nested deep inside the object.
Checkout Reverse polarity of an angular.js filter to see how you can use this for other useful operations with filter.
If you have created an AngularJs custom filter, you can send multiple params to your filter.Here is usage in template
{{ variable | myFilter:arg1:arg2... }}
and if you use filter inside your controller here is how you can do that
angular.module('MyModule').controller('MyCtrl',function($scope, $filter){
$filter('MyFilter')(arg1, arg2, ...);
})
if you need more with examples and online demo, you can use this
AngularJs filters examples and demo
This may be slightly irrelevant, but if you're trying to apply multiple filters with custom functions, you should look into:
https://github.com/tak215/angular-filter-manager
Example I have a students list as below :
$scope.students = [
{ name: 'Hai', age: 25, gender: 'boy' },
{ name: 'Hai', age: 30, gender: 'girl' },
{ name: 'Ho', age: 25, gender: 'boy' },
{ name: 'Hoan', age: 40, gender: 'girl' },
{ name: 'Hieu', age: 25, gender: 'boy' }
];
I want to filter students via gender to be boy and filter by name of them.
The first I create a function named "filterbyboy" as following:
$scope.filterbyboy = function (genderstr) {
if ((typeof $scope.search === 'undefined')||($scope.search === ''))
return (genderstr = "")
else
return (genderstr = "boy");
};
Explaination: if not filter name then display all students else filter by input name and gender as 'boy'
Here is full HTMLcode and demo How to use and operator in AngularJs example

Categories