Bind ng-options in ng-model on loading (like a bidirectional binding) - javascript

The situation:
I have the following select:
<select ng-model="model" ng-options="o as o.name for o in options track by o.code">
<option value="">- Default -</option>
</select>
My options datas are like this:
$scope.options = [{id: 1, code: 'foo', name: 'Foo!'}, {id: 2, code: 'bar', name: 'Bar!'}];
What I want to do:
I want to have my select with a pre-selected value. My constraint is that I only know the code attribute of my object. With the help of the track by notation I can do that simply like this:
$scope.model = {code: 'bar'};
And it works, the selected value of the select is "Bar!"
The problem:
When I send this data to my backend, I need to send the id attribute of my object. The data sent is {code: 'bar'} but not {id: 2, code: 'bar', name: 'Bar!'} as I want.
For me it is the normal behavior... because I stored in my model {code: 'bar'} and I did not change the value selected.
The conclusion:
Is there a way to tell to AngularJS to copy the value from the options list to model when there is a default value in model (when there is a match using the track by notation) ?
Info: I know that I can do something like this $scope.model = $scope.options[2] (with some logic to determine the index...) but I would like something more magical... If it is possible... :D

OP Info: I know that I can do something like this $scope.model = $scope.options[2] (with some logic to determine the index...) but I would like something more magical... If it is possible... :D
I have 3 magic's for your 3 objects
Magic 1 :
$scope.model = $scope.options.filter(function(item) {
return item.code=== 'bar';
})[0];
Magic 2:
app.filter('getById', function() {
return function(input, id) {
var i=0, len=input.length;
for (; i<len; i++) {
if (+input[i].id == +id) {
return input[i];
}
}
return null;
}
});
$scope.model = $filter('getById')($scope.options, 2);
Magic 3
angular.forEach($scope.options, function(option) {
$scope.model = option.name == "name";
if($scope.model !=null){break}
});

You need to add a ng-change on the <select> and then create a function that will look for the selected option and its corresponding JSON model. Use this
HTML
<div ng-app='app' ng-controller='mainCtrl'>
<select ng-model="model" ng-options="o as o.name for o in options track by o.code"
ng-change='getValue(this)'>
<option value="">- Default -</option>
</select>
</div>
CONTROLLER
angular.module('app',['QuickList']).controller('mainCtrl', function($scope){
$scope.options = [{id: 1, code: 'foo', name: 'Foo!'}, {id: 2, code: 'bar', name: 'Bar!'}];
$scope.model = {code: 'bar'};
$scope.getValue = function(item){
console.log($scope.selectedOption = item.model);
}
});
Whenever you will select the option in the <select> box you will see the actual JSON object for that option printed in the console.
Here is the working JSFIDDLE

Related

How to access array if I get the name of the array from a selected option?

I have a list of items:
<select id ="listSelector">
<option value="books">Books</option>
<option value="countries">Countries</option>
<option value="states">States</option>
<option value="presidents">Presidents</option>
</select>
Which correspond to arrays of items:
var books = ['genesis', 'exodus', 'leviticus', 'numbers'];
var countries = ['Akrotiri','Albania','Algeria','American'];
var states = ['Alabama','Alaska','Arizona','Arkansas'];
var presidents = ['Washington','Adams','Jefferson','Madison'];
I want to be able to select an item from the list and use the value of the item to select the correct array.
var listSelector = document.getElementById('listSelector');
var selectedList = listSelector.options[listSelector.selectedIndex].value;
console.log('selected', selectedList[0]);
// returns first letter of the value of the list that was selected
// instead of the first item in the array.
// Ex. If I selected the Books option, the value would be 'books'
// and I want to access the books array.
If you change the structure to an object instead, it would be quite easy
var stuff = {
books : ['genesis', 'exodus', 'leviticus', 'numbers'],
countries : ['Akrotiri', 'Albania', 'Algeria', 'American'],
states : ['Alabama', 'Alaska', 'Arizona', 'Arkansas'],
presidents : ['Washington', 'Adams', 'Jefferson', 'Madison']
}
var listSelector = document.getElementById('listSelector');
listSelector.addEventListener('change', function() {
var item_array = stuff[listSelector.value];
document.getElementById('result').innerHTML = '<pre>' + JSON.stringify(item_array, 0, 4) + '</pre>';
}, false);
<select id="listSelector">
<option value="books">Books</option>
<option value="countries">Countries</option>
<option value="states">States</option>
<option value="presidents">Presidents</option>
</select>
<div id="result"></div>
If you do console.log('selected',selectedList) you will notice that it is the string value for the selected option. So doing selectedList[0] when the selected item is "book" will return "b" since using array index notation on strings returns the character for the given index.
Right now your lists (books,contries,states,presidents) are all stored on the global object. For browsers this is defined as window. So you can access any of your declared variables with.
window.book
But we can also use Strings to access properties like this
window['books']
So when we get the string representation for the variable name that we want we can access it like so
window[selectedList]
This will give us the target array and we can then access properties on it.
window[selectedList][0]
So if "book" was selected the above code would return "genesis". To get your original intended value of selected list we can break this process into two steps by creating an intermediate variable to store the name of the target list
var selectedListName = listSelector.options[listSelector.selectedIndex].value;
var selectedList = window[selectedListName]
console.log('selected', selectedList);
We can go one step further and create our own object to store all the lists instead of using the global window object.
var lists = {
books : ['genesis', 'exodus', 'leviticus', 'numbers'],
countries : ['Akrotiri', 'Albania', 'Algeria', 'American'],
states : ['Alabama', 'Alaska', 'Arizona', 'Arkansas'],
presidents : ['Washington', 'Adams', 'Jefferson', 'Madison']
}
var listSelector = document.getElementById('listSelector');
var selectedListName = listSelector.options[listSelector.selectedIndex].value;
var selectedList = lists[selectedListName]
console.log('selected', selectedList);
<select id="listSelector">
<option value="books">Books</option>
<option value="countries">Countries</option>
<option value="states">States</option>
<option value="presidents">Presidents</option>
</select>

How can I filter a string array in ng-repeat with another string array?

I have a select element that I want to filter:
<select multiple="multiple" class="span2" data-ng-model="selectedParameters">
<option data-ng-repeat="parameter in availableParameters">
{{parameter}}
</option>
</select>
"availableParameters" is a string array that I can reach from here without problem, and "selectedParameters" is another string array that represents the selected elements in the UI.
availableParameters = ["AAA", "BBB", "CCC", "DDD"];
I have another string array under object graph (accessible inside the HTML)
graph.parameters = ["AAA", "BBB"];
I am trying to filter "availableParameters" by "graph.parameters" and obtain a list like this: "CCC", "DDD"
I checked AngularJS's documentation but couldn't see an example for my problem.
All I could do is something like this:
<option data-ng-repeat="parameter in availableParameters | filter: !graph.parameters ">{{parameter}}</option>
You can make a custom filter to filter out all of the items that aren't in graph.parameters:
angular.module('yourModuleNameHere').filter('params', [function(){
return function (items, filterBy) {
return items.filter(function(currentItem){
return filterBy.indexOf(currentItem) === -1;
});
};
}]);
Afterwards you can use it as:
<select multiple="multiple" class="span2" data-ng-model="selectedParameters">
<option data-ng-repeat="parameter in availableParameters | params:graph.parameters">
{{parameter}}
</option>
</select>
You can do it in many ways, a filter is useful when the data can change but I think that isn't your case, you just need to add a simple business login in your controller... have a look on what follows:
var rawlist = ['foo', 'baz', 'bar'];
var blacklist = ['baz'];
var list = rawlist.filter(function(item) {
return blacklist.indexOf(item) < 0;
});
console.log('available parameters are', list);
so, your view can be:
<select ng-model="someScopeProperty" ng-options="item for item in list track by $index"></select>

Knockout Js Array.removeAll() not working

var x=ko.observableArray([....]);
x.removeAll();
Situation is 'x' is holding the selected values from dropdowns which are dynamically generated using knockout. I want to clear all the selections made by the user.
The above code is not working in my situation, so i have to 'undefine' each element in the array using a for loop - which is a very bad way(i feel). i want to know if there any better way of doing this?
I also tried this:
x([]);
Which didn't work either.
My code Looks something like this
var data_Main = [
{[a,b,c] },{[d,e,f]},{[g,h,i]}
];
var selectedKoArray= ko.observableArray([]);
var Lst=ko.observableArray([
{Txt: 'aaa', Val: 'a'},
{Txt: 'bbb', Val: 'b'},
{Txt: 'ccc', Val: 'c'}
]);
var dataArray = ko.observableArray([Lst:Lst(), Lst:Lst1(), Lst:Lst2()]);
var selectedHFilters = ko.observableArray([]);
for (var i = 0; i < dataArray.length - 1; i++) {
if (selectedKoArray[i])
selectedKoArray[i] = undefined;
}
-----------------------------------------------------HTML-------------------------------
<div data-bind="foreach:dataArrayKO ">
<select class="select2-offscreen filter-select" data-bind="options:Lst, optionsText: 'Txt', optionsValue: 'Val', optionsCaption: '-Select-', value:$root.selectedHFilters[$index()]"></select>
</div>
This is not valid Javascript and will error, which may be the root of your problem:
var dataArray = ko.observableArray([Lst:Lst(), Lst:Lst1(), Lst:Lst2()]);
I suspect you wanted something like this (though Lst(), Lst1() and Lst2() are not defined in the code you've supplied, again this will error).
var dataArray = ko.observableArray([Lst.Lst(), Lst.Lst1(), Lst.Lst2()]);
The KO code for removing elements you have supplied is fine.

angularjs ng-model and ng-select strange behaviour

I have a list of persons objects that I want to bind to a select element.
Controller implementation:
// Person controller
function PersonCtrl($scope) {
$scope.persons = [{id: 1, name: 'alex'}, {id: 2, name: 'jhon'}];
$scope.selectedPerson = {id: 2, name: 'jhon'};
}
Html markup:
<select ng-model="selectedPerson" ng-options="p.name for p in persons"></select>
The problem is that the binding seems to work only from the HTML to the scope and not the other way around. If I select an item from the drop down, it will correctly update the $scope.selectedPerson. But, if I initially set the value of the $scope.selectedPerson variable to one of the objects in the persons list, the value will not be reflected on the select control.
I also have fiddle that shows exactly what the problem is: http://jsfiddle.net/nE3gt/
Thank you in advance!
You need to set the selectedPerson to an element in the persons array, not a new object - otherwise Angular has no idea they are the same thing.
// Person controller
function PersonCtrl($scope) {
$scope.persons = [{id: 1, name: 'alexx'}, {id: 2, name: 'jhon'}];
$scope.selectedPerson = $scope.persons[1];
$scope.submit = function () {
//console.log(JSON.stringify($scope.Person));
$("#obj").text(JSON.stringify($scope.Person));
};
}
Updated fiddle: http://jsfiddle.net/nE3gt/2/
edit
If I'm understanding you correctly, you want to do something along these lines:
// Person controller
function PersonCtrl($scope) {
//serverData is the result of some http request...
var serverData = {persons: [{id: 1, name: 'alexx'}, {id: 2, name: 'jhon'}], selectedPerson: {id: 2, name: 'jhon'}};
$scope.persons = serverData.persons;
$scope.selectedPerson = null;
//find obj in persons that equals selectedPerson
for(var i = 0, l = serverData.persons.length; i < l; i++)
{
if(serverData.persons[i].id === serverData.selectedPerson.id)
{
$scope.selectedPerson = serverData.persons[i];
}
}
$scope.submit = function () {
//console.log(JSON.stringify($scope.Person));
$("#obj").text(JSON.stringify($scope.Person));
};
};
Even if your data comes back as different objects you need to make sure you're setting selectedPerson to an item that is in the persons array.
new fiddle: http://jsfiddle.net/nE3gt/4/
Set it to the index of the array you're binding to:
$scope.selectedPerson = $scope.persons[0];
Demo: http://jsfiddle.net/nE3gt/3/

ngOptions: add tooltip to selection

using the following json collection:
$scope.searchscope = [
{ id: 0, name: "Base", description: "Search only the specified base object. The value is equal to 0." },
{ id: 1, name: "OneLevel", description: "Search the child objects of the base object, but not the base object itself.The value is equal to 1" },
{ id: 2, name: "Subtree", description: "Search the base object and all child objects. The value is equal to 2" }
];
and the following markup
<select data-ng-model="mySelections[0].SearchFilterMembershipsScope" data-ng-options="i.id as i.name for i in searchscope" data-ng-required="true"></select>
I have successfully generated a select with the 3 options. What would be the best angular way to display a tooltip of the currently selected items "description"? Also would it be possible to do this whilst the user is navigating the dropdown, i.e. making a choice, verses actually had made the choice?
You would need a map from id → description. One way to populate it would be:
$scope.idToDescription = null;
$scope.$watch("searchscope", function(newval) {
if( newval != null ) {
$scope.idToDescription = {};
var i;
for( i=0; i < newval.length; i++ ) {
$scope.idToDescription[newval[i].id] = newval[i].description;
}
}
});
And in your template use it as:
<select ...
title="{{ idToDescription[mySelections[0].SearchFilterMembershipsScope] }}">
If you are using Twitter Bootstrap, you might also consider looking at Tooltips in
UI Bootstrap and if you want fancier select boxes consider using ui-select2 based on Select2.

Categories

Resources