Angularjs - how to see if a value is in array? - javascript

I have a model similar to this one:
model = [
{
name: 'Chris',
age: '29',
approvedBy: ['id1', 'id2', 'id3']
},
{
// repeat...
}
]
in my view I have a ng-repeat for the model and there is a button to approve or disapprove the user.
Basically other users can approve or disapprove, if previously approved, the user. Quite similar to like or unlike a FB post.
<div ng-repeat='user in model'>
<p>Name: {{user.name}} - Age: {{user.age}}</p>
<p>Approved by {{user.approvedBy.length}} users.</p>
<button>Approve {{user.name}}</button>
</div>
It works fine, so I can approve and disapprove the user but I can not figure out how can I change the text of Approve.
I wish it to be Disapprove if has already been approved by the user in the session.
I'm looking for something like indexOf to create an inline if... or a filter...
It should look like:
<button>(user.approvedBy.indexOf(currentUserId)) ? 'Disapprove' : 'Approve'</button>
How can I create something like that in Angularjs?

A simple approach would be:
Add a custom filter to the controller and then use it in the view:
In controller:
$scope.model = [...];
$scope.approveTextFilter = function (user) {
return user.approvedBy.indexOf(currentUserId) !== -1 ? 'Disapprove' : 'Approve';
};
In view:
<div ng-repeat='user in model'>
...
...
<button ng-bind="user | filter:approveTextFilter"></button>
</div>

Related

Angular 4 check multiple checkboxes

I have a form with User roles displayed as multiple checkboxes:
<div *ngFor="let role of roles">
<label for="role_{{role.id}}">
<input type="checkbox" ngModel name="roles" id="role_{{role.id}}" value="{{role.id}}"> {{role.name}}
</label>
</div>
the roles object loaded from server looks like this which have all the roles that displayed on the form:
{id: 1, name: "HQ", description: "A Employee User", created_at: "2017-10-07 10:43:17",…}
1
:
{id: 2, name: "admin", description: "A Manager User", created_at: "2017-10-07 10:43:17",…}
2
:
{id: 3, name: "caretaker", description: "", created_at: null, updated_at: null}
now i want to set multiple check boxes using form.setValue, my user object loaded from server looks like this:
"roles" in the user object are the roles that are assigned to the user and needs to be checked on the form
{
"id":13,
"name":"Wasif Khalil",
"email":"wk#wasiff.com",
"created_at":"2017-10-07 10:43:17",
"updated_at":"2017-10-09 07:45:34",
"api_token":"LKVCGPGnXZ3LyiCnyiTAg8XTpck6xWlVkeoMBgtoYZWoAOy4b5epNqMz7KG7",
"roles":[
{"id":2,"name":"admin","description":"A Manager User","created_at":"2017-10-07 10:43:17","updated_at":"2017-10-07 10:43:17","pivot":{"user_id":"13","role_id":"2","created_at":"2017-10-07 10:43:17","updated_at":"2017-10-07 10:43:17"}
},
{"id":1,"name":"HQ","description":"A Employee User","created_at":"2017-10-07 10:43:17","updated_at":"2017-10-07 10:43:17","pivot":{"user_id":"13","role_id":"1","created_at":null,"updated_at":null}
}
]
}
after loading user object form server im setting values like this:
this.form.setValue({
name: user.name,
email: user.email,
password:"",
confirm_password:"",
roles: [1] //here im not sure how to set roles
});
can someone help me check the checkboxes with the loaded user roles object.
Thanks in advance
EDIT:
Sorry for not explaining it well, i have edited my question to explain the question again:
the roles on user object are the roles that are assigned to user
and the roles object is the list of all roles to display in form, look at the image below:
You don't have to use reactive forms to make it done.
HTML
<input ...[checked]="check(user.roles,role.id)" ...>
Typescript:
check(value1, value2){
return (value1.filter(item => item.id == value2)).length
}
DEMO

AngularJS filter as selector from array

I'm having two array in my scope: employees and cars. Every employee has a carId which matches a car out of the cars-array.
Employee looks like
[{'id': 1, 'name': 'John', 'carId': 1}]
Car like
[{'id': 1, 'color': 'red'}]
Now I have an ng-repeat and would like to output the color of the car directly with an filter:
{{ employee.carId | selectFromCars:$scope.cars }}
I don't know how to get access to the cars array inside the filter. Is this even possible or should I inject the car into the employee after loading and then just use following?
{{ employee.car.color }}
you can make your own custom filter and just add it the end of your controller like so:
.filter('empCarFilter', function() {
return function(carId, cars) {
// you can access $scope.cars here, for example...
angular.forEach(cars,function(value){
if (value.id === carId) {
return value.color;
}
// etc...etc...
})
}
The above method is under the assumption that you are passing employee.carId into the filter. But, not sure how useful this would be for you, but you can pass the whole object to the filter as well and not just one key with:
{{ employee | empCarFilter }}
Here is also a pretty good reference for custom filters:
https://scotch.io/tutorials/building-custom-angularjs-filters

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.

Efficient queries for multiple corresponding documents using an array of _id references

I'm trying to grok Meteor. Here's a helper that I have in one of my templates:
genres: function() {
return Genres.find();
}
Which returns something like this:
[{ "name" : "Action", "_id" : "CHP8uaSPNwKTj6gn7" },
{ "name" : "Thriller", "_id" : "8hKRp3LmgcD6gPRXf" }]
I have yet another helper function in that same template:
authors: function() {
return Authors.find();
}
Which returns something like this:
[{ "name" : "Robert Ludlum", "genre" : [ "CHP8uaSPNwKTj6gn7", "8hKRp3LmgcD6gPRXf" ]}]
The problem becomes clear when I want to display authors and their genres in HTML:
{{#each authors}}
<p> Author: {{name}} </p>
<p> Genres: {{genre}} </p>
{{/each}}
Which, as you've already guessed, results in:
Author: Robert Ludlum
Genres: CHP8uaSPNwKTj6gn7, 8hKRp3LmgcD6gPRXf
And that's not desirable. This would much be better:
Author: Robert Ludlum
Genres: Action, Thriller
I've had a tough time figuring out how to accomplish that. I don't have a lot of experience with this NoSQL stuff and the examples that I've seen have been unhelpful in this context.
So how do I pull that off?
There are a few ways to solve this. One is to add a helper like:
Template.myTemplate.helpers({
genreNames: function() {
var genres = Genres.find({_id: {$in: this.genre}}).fetch();
var names = _.pluck(genres, 'name');
return names.join(', ');
}
});
And modify your template to look like this:
{{#each authors}}
<p> Author: {{name}} </p>
<p> Genres: {{genreNames}} </p>
{{/each}}
The helper works because it runs inside of the #each so it's context is an author.
Alternatively, you can add a transform to your collection or use collection-helpers. That way, you can add a virtual property to all author instances, so you can do things like: Authors.findOne().genreNames().
In atmosphere there is a package called publish-composite, https://atmospherejs.com/reywood/publish-composite that should allow you to do what you are after.
It will allow you to select on multiple collections using a primary collection and related data from other collections.

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