AngularJS Select preselect not working - javascript

Preselection is not working in the select field even though the objects are equal:
<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee"
ng-model="todo.assignee" required
ng-options="user.name for user in users">
</select>
todo.assignee contains a user object, which should match one from users.
It seems that Angular does not recognize that the User object from todo.assignee is contained in users. Can I perform this mapping manually?
The select is shown with no value selected. I can choose a user (from users) and save the record without any problem.
Controller
$scope.todos = Todo.query();
$scope.users = User.query();
Update
As requested in the comments. Structure of the given objects:
$scope.todos
[
{
"id": 157,
"description": "my description 0",
"deadline": 1392073200000,
"assignee": {
"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"
},
"comment": "my comment 0",
"done": true
}
...
]
$scope.users
[
{
"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"
},
{
"id": 35,
"name": "User 2",
"email": "xxc#gmail.com"
},
{
"id": 36,
"name": "User 3",
"email": "xx#hotmail.com"
}
]
The scope of the select comes from a repeat:
<tr ng-repeat="todo in todos | filter:query | filter:{assignee:queryAssignee} | filter:queryDone" ng-class="{danger: isDue(todo)}">
<td>

According to your description:
todo.assignee contains a user object
But your options' value are user.name strings, one object and one string will never be matched.
So, replace
ng-model="todo.assignee"
to
ng-model="todo.assignee.name"
UPDATE:
use ng-options="user.name as user.name for user in users"
Full Answer:
<select ng-show="isEditMode(todo.id)"
ng-model="todo.assignee.name" required
ng-options="user.name as user.name for user in users">
</select>
Plnkr:
http://plnkr.co/edit/A1XdMYmACNCr3OwBuFhk?p=preview
select as label for value in array
label: The result of this expression will be the label for element. The expression will most likely refer to the value variable (e.g. value.propertyName).
you can have refer here:
http://docs.angularjs.org/api/ng.directive:select
UPDATE2:
To fix the side effect, you can use option with separated value and display name
<select ng-model="todo.assignee" required>
<option ng-repeat="user in users" value="{{user}}" ng-selected="todo.assignee.name === user.name">
{{user.name}}
</option>
</select>
Plnkr:
http://plnkr.co/edit/6tzP9ZexnYUUfwAgti9b?p=preview
Explanation:
Before:
When you select one of option, it assign option value to model todo.assignee.name, so only change the name.
todo.assignee.name = "User 3" // like this
todo.assignee // didn't change the id & email
/* {"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"} */
But, Now:
When you select one of option, it assign object value to model todo.assignee, so let what you want.
todo.assignee.name = {
"id": 36,
"name": "User 3",
"email": "user3#hotmail.com"
} // like this
todo.assignee // now change the whole value
/* {"id": 36,
"name": "User 3",
"email": "user3#hotmail.com"} */

Maybe it can be useful for someone else:
<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee"
ng-model="todo.assignee" required
ng-options="user as user.name for user in users track by user.id">
</select>
The magic trick is in "track by user.id"
https://docs.angularjs.org/api/ng/directive/ngOptions

Related

Allow for conditional .filter() and .map() in AngularJS on-change?

I have a problem where I am unable to edit the actual script of the page. That means I cannot add an AngularJS filter, directive, and so on. I am pretty limited, so I can only edit the HTML.
I want to be able to, based on the input from a dropdown, filter an existing list based on the selected property. This is relatively easy, and it can be done like this:
myArray.filter(x => x.Type == selectedType)
However, AngularJS throws up an error, because it won't allow me to use either .filter(function(){}) or .filter(x => x). At first I thought it was a problem with lambda, since AngularJS might not support that, but it turns out it's basically impossible to filter an array based on its properties.
This is my initial object:
[{
"id": "random",
"type": "1",
"name": "First tag"
},
{
"id": "random-2",
"type": "1",
"name": "Second tag"
},
{
"id": "random-3",
"type": "2",
"name": "Third tag"
}]
and if I do .filter(x => x.type = "2"), I should be able to get this list back:
[{
"id": "random-3",
"type": "2",
"name": "Third tag"
}]
Take a lookt at this Plunker: https://embed.plnkr.co/yudKIhsB2OQ9Phh0X1am
The "Filtered tags" in the HTML should show the filtered tags based on this condition (which works in normal JavaScript-language):
ng-change="vm.FilteredTags = vm.Tags.filter(x => x.type == vm.SelectedValue)"
You can filter out type property value which is matching vm.SelectedValue.
<p>Filtered tags: {{vm.Tags | filter: {type: vm.SelectedValue}: true }}</p>
Or using alias it would be way simpler, no need to have it on ng-change.
<div ng-repeat="vm.Tags | filter: {type: vm.SelectedValue}: true as FilteredTags">
... your sutff here...
<div>

angularjs filter with an "OR" operation on data when we have multiple filters

I checked other question but they don't seem to solve my issue.
Here is my code :
var app = angular.module('myApp', []);
app.controller('listdata', function($scope, $http) {
$scope.users = [{
"name": "pravin",
"queue": [{
"number": "456",
"status": "Unavailable"
},
{
"number": "111",
"status": "Unavailable"
}],
"phone": "7411173737"
},
{
"name": "pratik",
"queue": [{
"number": "111",
"status": "Unavailable"
}],
"phone": "8558855858"
},
{
"name": "priyanka",
"queue": [{
"number": "456",
"status": "Unavailable"
}],
"phone": "5454573737"
},
{
"name": "prerana",
"queue": [{
"number": "111",
"status": "Unavailable"
}],
"phone": "7454543737"
}];
$scope.filter111 = function (user) {
return (user.queue.find(({number}) => number === '111'));
}
$scope.filter456 = function (user) {
return (user.queue.find(({number}) => number === '456'));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.0/angular.min.js"></script>
<div ng-app="myApp">
<label class="switch">
<input type="checkbox" ng-model="queue111">111
</label>
<label class="switch">
<input type="checkbox" ng-model="queue456">456
</label>
<div class="row" ng-controller="listdata">
<div ng-repeat="user in users|filter: queue111? filter111: ''|filter: queue456? filter456: ''">
<p> {{user.name}} {{user.phone}}</p>
</div>
</div>
</div>
I have created custom functions $scope.filter111 and $scope.filter456 respectively to filter data
Currently when I click the checkbox 111, the filter return only the record whose queue has a number 111 and when I click the checkbox 456, the filter returns only the records whose queue has a number 456. This much is working perfectly. When I click both the filters it displays only that object whose queue has both the number 111 and 456 i.e an AND operation is occurring here.
Expected result : I want it such that when I click both the checkbox
it should display all the records from 111 as well as 456 together i.e an OR operation.
How do I do this?
You can try creating a custom angularJS filter by referring w3schools.com example and this link (for better understanding of custom filters).
In your case, the custom angularjs filter would take 3 inputs, i.e the list you want to filter and the value of the checkboxes- queue111 and queue456. Perform filtering and returning the data by providing necessary conditions based on the value of checkboxes inside the filter.
This also reduces the code that you use in your HTML for filtering inside ng-repeat from
<div ng-repeat="user in users|filter: queue111? filter111: ''|filter: queue456? filter456: ''">
<p> {{user.name}} {{user.phone}}</p>
</div>
to
<div ng-repeat="user in users|customFilter: queue111:queue456">
<p> {{user.name}} {{user.phone}}</p>
</div>
where
customFilter is the name (can be any name, provided that name as
an example) of the angularJS filter you create.
users will be the default first input of your custom filter and the value of your checkboxes will be the 2nd and 3rd input respectively.
Also, it would be helpful if you provide codepen/plunker demos so that people can debug your problem and provide solutions easily.

Dynamic select options unique to their parent using underscore.js template

This is my code fiddle below:
https://jsfiddle.net/ost9area/
This is what I'm trying to do:
I created three arrays for the data:
filterFields = {
"group.name": "Group name",
"group.effective_status": "Group status",
"subgroup.name": "Subgroup name",
"subgroup.effective_status": "Subgroup status",
"person.name": "Person name",
"person.effective_status": "Person status",
}
filterOperators = {
"name": {
"CONTAIN": "Contains",
"NOT_CONTAIN": "Doesn't contain"
},
"effective_status": {
"status.IN": "is",
"status.NOT_IN": "is not"
}
}
filterStatuses = {
"group": {
"ACTIVE": "Active",
"PAUSED": "Paused"
},
"subgroup": {
"ACTIVE": "Active",
"PAUSED": "Paused",
"GROUP_PAUSED": "Group Paused"
},
"person": {
"ACTIVE": "Active",
"PAUSED": "Paused",
"GROUP_PAUSED": "Grpup Paused",
"SUBGROUP_PAUSED": "Subgroup Paused"
}
}
The concept is, when the name is selected in the first field, the contains is selected in second and textbox should appear in the third. However, when effective_status is selected in the first field, the status is selected in second field and third is also select menu. I did that, and I also managed to make the multiple conditions there. But, only first of the boxes work. I can make all the boxes work, by setting up individual id for each field dynamically.
I'm not sure if that's the right way to go. I already have 22 lines of javascript and 3 underscore templates just to do that. I'm looking for a guide to do this the right way. Also, please keep in mind that when Save Changes is clicked, I'm planning to send the data to the root page (before popup).
How can we handle conditions like this properly? When an unlimited number of fields can be added, and one field is manipulated by another.

AngularJS Dynamically Creating Select Box - ngModel Not Registering

I am using one select box to conditionally generate a second select box. The select boxes populate correctly and everything looks okay in the Chrome Inspector on the elements.
The problem is the ng-model (ng-model="commandName" in the code example below) does not properly register the correct select value. So, if you look in the example, the {{commandName}} output at the end correctly outputs for the first select box but for the second select box nothing is output.
Is this a bug? Can anyone recommend an alternate method for approaching this problem?
Everything appears to work except commandName does not output anything in the p tag at the bottom but commandType does.
<select ng-model="commandType" class="form-control" ng-init="commandType = ''; command = ''">
<option value=""></option>
<option ng-repeat="commandGroup in commandList" value="{{$index}}">{{commandGroup.name}}</option>
</select>
<!-- Shown if something is selected in the select box above -->
<select ng-model="commandName" class="form-control" ng-if="commandType !== ''">
<option value=""></option>
<option ng-repeat="exactCommand in commandList[commandType].commands" value="{{$index}}">{{exactCommand.name}}</option>
</select>
<p>{{commandName}}</p>
AngularJS code:
$scope.initCommandList = function () {
$http({
method: 'GET',
url: $rootScope.webserver + 'admin/rterminalCommandList/',
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data) {
console.log("Command list");
console.log(data.data);
$scope.commandList = data.data;
});
};
$scope.initCommandList();
And POST response:
{
"data"
:
[{
"id": 2,
"name": "Application",
"commands": [{
"id": 3,
"name": "Delete Smartcare data",
"syntax": "su -c pm clear com.patasonic.android.smartcare",
"comment": "Deletes Smartapp data"
}]
}, {
"id": 1,
"name": "Bluetooth",
"commands": [{
"id": 2,
"name": "Bluetooth Controls. Turn off",
"syntax": "bluetooth# off",
"comment": "Turns off device bluetooth"
}, {"id": 1, "name": "Bluetooth Controls. Turn on", "syntax": "bluetooth# on", "comment": "Turn on bluetooth"}]
}], "header"
:
{
"messages"
:
[], "response_code"
:
200
}
}
I recommend you to use "select ng-options" instead of "option ng-repeat"
https://docs.angularjs.org/api/ng/directive/ngOptions
<select ng-model="myModel"
ng-options="command as command.name for command in commandList">
</select>
Here is a jsfiddle with an example:
http://jsfiddle.net/jcamelis/5y086ytr/4/
I hope it helps.

ng-repeat filter by existing array values

so I'm working with a basic product category model to get my head around filtering and I can't figure out how to extract a property value from one object within an array while repeating through another.
A simplified version of my category array, which is in scope, looks like this. I can output their names with the preceding directive and the results are as expected:
[{
"_id": "TY76",
"name": "Planes"
}, {
"_id": "887T",
"name": "Trains"
}, {
"_id": "A0K4",
"name": "Autos"
}]
<p ng-repeat="category in product.categories "> {{ category.name }}</p>
And here is a simplified product, also in scope, which may contain the ID of one or more categories. In this case, Bobble Head belongs to both Planes and Autos:
{
"_id": "9876",
"name": "Bobble Head",
"cats": "['TY76','A0K4']"
}
Now, here is where I'm having a hard time. I need to output the category names with the product. I can output the IDs no problem via:
<p ng-repeat="cat in product.cats ">{{ cat }}</p>
But that's of no use to the end user but I have no idea how to end up with something like:
Product: Bobble Head | Categories: Planes, Autos
I don't have the autonomy to add the category name to each product and I've tried a bunch of different filtering approaches but I don't think I'm wording my question right or something because I'm not finding much on the interwebs about this.
Any ideas?
Sounds like you want to build up a lookup for category id to category name:
var categories = [{
"_id": "TY76",
"name": "Planes"
}, {
"_id": "887T",
"name": "Trains"
}, {
"_id": "A0K4",
"name": "Autos"
}];
// build a category lookup id -> name
var categoryLookup = {};
categories.forEach(function(category) {
categoryLookup[category._id] = category.name;
});
Here's a full working fiddle: http://jsfiddle.net/02qadem7/1/
You can create a key-pair object where the key is the id and the value is the name of the category:
var categoriesArray = [{
"_id": "TY76",
"name": "Planes"
}, {
"_id": "887T",
"name": "Trains"
}, {
"_id": "A0K4",
"name": "Autos"
}];
$scope.categoriesMap = {};
categoriesArray.forEach(function(category) {
$scope.categoriesMap[category._id] = category.name;
});
Then in your view you can access the category name like this:
<div ng-repeat="product in products">
<strong>Product: </strong> {{product.name}} |
<strong>Categories: </strong> <span ng-repeat="category in product.cats">
{{categoriesMap[category]}}
</span>
</div>
Here's a plunkr: http://plnkr.co/edit/BpBcCizzU2Vh8VPniiHA?p=preview
I sugest using a custom filter on categories array.
myApp.filter('byCategoryIds', function() {
return function(categories, catIds) {
return categories.filter(function(item) {
return (catIds.indexOf(item._id) != -1);
});
};
});
Then you can iterate on categori array sending ids array like so:
<b>Product:</b>
{{product.name}};
<b>Categories:</b>
<span ng-repeat="cat in categories | byCategoryIds: product.cats">{{ cat.name }}, </span>

Categories