ng-model changes all select at once - javascript

jsfiddle
Hi.
I have a problem with my application. I have to write several selects by using ng-repeat and each of these selects must be filled with the same data.
The problem is, when the one is changed, others selects are changes to the same value - why?.
I suppose that the problem is in the ng-model - maybe I don't understand how the "hierarchy" of the ng-model works.
If the name of the ng-model is only "option" - it doesn't work!
If the name of the ng-model is "something.option" - it also doesn't
work!
If the name of the ng-model is "something.else.option" - it does work
but all selects are filled!
HTML:
<div ng-controller="MyCtrl">
<div ng-if="models" ng-repeat="m in models">
<br><label>{{m.model}} ({{m.no}})</label><br>
<select ng-model="models.m.opModel" ng-options="opt.value as opt.text for opt in options" ng-change="foo()"></select>
</div>
</div>
JS:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.models = [
{'no':'A', 'model':'alpha'},
{'no':'B', 'model':'beta'},
{'no':'C', 'model':'gamma'}
];
$scope.options = [
{'value':1, 'text':'one'},
{'value':2, 'text':'two'},
{'value':3, 'text':'three'}
];
$scope.foo = function(){
alert($scope.models.m.opModel);
}
}
What am I doing wrong?
Thanks a lot.

You've created a scope object called "m" which is the current child of the "models" list. So for each dropdown, you're going to have a different "m" scope object. This is what you need to bind to in your ng-model so that the dropdown is bound to its unique parent in the "models" list.
Change <select ng-model="models.m.opModel"> to <select ng-model="m.opModel" to fix the problem.
To access the value with the foo() function, you'll need to use this updated function:
$scope.foo = function(index){
alert($scope.models[index].opModel)
}
And update the <select> like this:
<select ng-model="m.opModel" ng-options="opt.value as opt.text for opt in options" ng-change="foo($index)"></select>
You're creating an ng-model called "opModel" in the ng-repeat which means you'll have three new opModels under $scope.models. This is an array you can access later using an index value to specify which of the $scope.models[].opModel you want to access.
Notice that I've changed the ng-change code to send the current $index which is basically an ng-repeat counter. So your foo() function will receive either a 0, 1 or 2 which lets us access the specific ngModel that we need to access.

You are binding to the single object models. Inside an ng-repeat the repeated is available "in scope". You probably want to change this code to:
<div ng-controller="MyCtrl">
<div ng-if="models" ng-repeat="m in models">
<br><label>{{m.model}} ({{m.no}})</label><br>
<select ng-model="m.opModel" ng-options="opt.value as opt.text for opt in options" ng-change="foo()"></select>
</div>
</div>
Look at the ng-model="m.opModel", that is what I've changed. You are now updating the value of the single item, and not inserting a new object into an array which is then reused by all the ng-repeat items (which is why all the values would update at the same time).

Related

How to make angular child scopes refresh?

I have a template:
<div class="oss-object cp-def cp-row" ng-repeat="(key, value) in data" ng-init="viewables = getViewables(value.versions[0].objectInfo);">
<div class="cp-def">
{{value.info.name}} OssStatus: {{value.versions[0].objectInfo.status}}
, 3D-Viewables:
<select ng-change="viewableSelected(value.versions[0].urn, viewables, '3d')" ng-model="viewables.selected3d" ng-options="viewable as viewable.name for viewable in viewables['3d']">
<option value="">---Please select---</option>
</select>
, 2D-Viewables:
<select ng-change="viewableSelected(value.versions[0].urn, viewables, '2d')" ng-model="viewables.selected2d" ng-options="viewable as viewable.name for viewable in viewables['2d']">
<option value="">---Please select---</option>
</select>
</div>
</div>
And when data gets updated (the data property used in the top ng-repeat) in my controller with a new data set, it doesn't automatically refresh the child scopes in the ng-options. which are derived from the data set. Does anyone know how to refresh child scopes? I have tried calling $apply and $digest but with no success.
As I said in the comments, you could try to replace viewables['3d'] in the ng-options with getViewables(value, '3d') and have the controller return the array.
If you look at the docs for ngInit, you'll see they basically say "never use this except in nested ngRepeats".
One way to do what you want is to create a controller for each repeated item, and create a $watch on the data that changes (or expression in this case), and set viewables equal to that.
eg
function ViewablesCtrl($scope){
$scope.$watch($scope.getViewables, function(){$scope.viewables = $scope.getViewables($scope.value.versions[0].objectInfo);}
})
--
<div class="oss-object cp-def cp-row" ng-repeat="(key, value) in data" ng-controller="ViewablesCtrl()">

knock out foreach binding with independent varriable

I am using knockout for binding in my html5 application.
I have one strange scenario.
One div i am binding using for loop like below
<div data-bind="foreach: oneList">
<select name="dropDown1" id="dropDown1" data-bind="options: ddList,optionsText: function(item) { return item.value;},optionsValue:function(item) { return item.key; }">
</select>
<input type="text" id="newValue" data-bind="value : oneValue"/>
</div>
Here oneList is diffent varriable and ddList is a diffent varriable,both are independent varriable.
So when actual binding happens drop down does not get binded but input text is binded because oneList.oneValue is valid but oneList.ddList is not valid
Please let me know if my question is not clear
Without seeing your view-model it is quite hard to tell, but most probably there is no ddList property defined on items in the oneList list.
Inside a foreach binding the current binding context refers to the current item from the list so if you need to "go up" in the binding context to access a property which is on the same level as your onlist then you need to use $parent (or $root to access your main view-model).
A fixed options binding would look like this:
<select data-bind="options: $parent.ddList, optionsText:... " >

Bind checkbox or multi-select dropdown to array in AngularJS?

I am new to AngularJS, and am thus confused as how to bind checkboxes or multi-select dropdowns to a separate list.
<body ng-controller="FooListCtrl">
<span ng-repeat="foolist in foos">
<select ng-model="selected" ng-options="foo for foo in foolist" multiple="">
</select>
</span>
</body>
'use strict';
function FooListCtrl($scope) {
$scope.foos = {"Bar": [ "foo", "bar"]};
$scope.selected = [];
}
FooListCtrl.$inject = ['$scope'];
Run the code: http://jsfiddle.net/gBcN2/
If I got right what you want:
You don't have ng-app definition.
On jsFiddle for snippets of AngularJS put No wrap - in <head> load mode, if you are using AngularJS as external resource.
Model selected has it's own "range", because you use ng-repeat. To see what I mean, here is fixed version of your code:
http://jsfiddle.net/gBcN2/2/
First {{selected}} works fine, but second is "outside" of ng-repeat scope.
PS:
You don't have to use ng-repeat if you want to use it like you wrote in your example: quick fiddle of how I'd do it.
Edit:
For checkboxes it's something like that - http://jsfiddle.net/qQg8u/2/

Empty first element in dropdown list

I am quite a beginner with AngularJS and currently I am working on a web application in Django where I use AngularJS for the frontend part i can say. My problem is that the dropdown list which is populated with objects from a scope always start with a blank element (if i select one from the list, the issue is gone). This create problems because if the user doesn't select anything the POST request normally it will not work anymore. I would like to know how to have something like a preselected value or something similar. Here's part of my code:
Select tag:
<select id="sel" class="input-block-level" ng-model="list_category">
<option ng-repeat="obj in list_categories.data" value="{{obj.id}}">{{obj.name}}</option>
<option value="Other">Other</option>
</select>
$scope.list_categories:
var listcategoryPromise = ListCategory.get();
listcategoryPromise.then(function(response) {
$scope.list_categories = {
meta : response.data.meta,
data : response.data.objects
};
});
Use the directive ng-options and remove the value from the 'Other' option, like this:
<select id="sel" class="input-block-level" ng-model="list_category" ng-options="obj.id as obj.name for obj in list_categories.data">
<option value="">Other</option>
</select>
This ensures that if list_category is empty (no entry selected), the 'Other' option is selected (by default).
jsFiddle: http://jsfiddle.net/bmleite/gkJve/
Find the below working example below you should avoid ng-repeat with options
so please see below sample code with
<body ng-controller="testcontroller">
<select ng-model="item" ng-options="item.ID as item.Title for item in items">
</select>
<span>{{item}}</span>
</body>
App.controller('testcontroller', function ($scope) {
$scope.item = '000001';
$scope.items = [
{ ID: '000001', Title: 'Chicago' },
{ ID: '000002', Title: 'New York' },
{ ID: '000003', Title: 'Washington' }
];
});
You can use a specific syntax for <select> tags with Angularjs.
Inspired from the documentation page:
<select id="sel" class="input-block-level" ng-model="list_category" ng-options="obj.name for obj in list_categories.data">
<option value="Other">Other</option>
</select>
Here's some code directly from the AngularJs.org website about select lists:
<select ng-model="color" ng-options="c.name for c in colors"></select>
First, as you can see, you don't need to use the ng-repeat to build your options list. Angular is going to basically let you do a foreach loop on a collection to build your option list. Second, you have the ng-model which is on the select, but isn't the same as your collections name. This is going to be your item which is actually collected at post time .
function MyCntrl($scope) {
$scope.colors = [
{name:'black', shade:'dark'},
{name:'white', shade:'light'},
{name:'red', shade:'dark'},
{name:'blue', shade:'dark'},
{name:'yellow', shade:'light'}
];
$scope.color = $scope.colors[2]; // red
}
Okay, and here's the javascript controller code. $scope.colors is the collection and $scope.color is the model property which has been assigned to the select list in the html. As you can see from this example the model property is being given a default starting value of the third option in the array. For you, this can be set from the http.get you're using for loading up your page initally.
Now when you're doing the foreach, you're basically grabbing the 'name' value from the collection and you're saying 'show this value' in the dropdown and use this value on the post. By having that inital model property set, you should be able to avoid having an empty option field in your drop down list.
Reference: AngularJS Select
in my opinion this answer is cleaner:
$scope.form = {type : $scope.typeOptions[0].value};
http://jsfiddle.net/MTfRD/2010/
The Blank empty option on top of drop down will appear if you have set ng-model with some value which is not contained in the list options created after the ng-Repeat.
Now if you consider the original post and remove the ng-model or set some valid value in ng-model, it will work fine
or you can set selected first item as
$scope.list_category = $scope.list_categories.data[0].id;

Using AngularJS, how do I bind a <select> element to an attribute that updates via a service

I have a display controller and a management controller. Inside my display controller, I have a dropdown selector with the list of items that have been selected.
I can get the display area dropdown to update the list, adding items as they are added in the management controller, but I cannot figure out how to select the newest item in the dropdown.
<div ng-controller="MyDisplayCtrl">
<select ng-model="item" ng-options="i.name for i in items">
</select>
</div>
I have made a jsfiddle to illustrate my situation. Ultimately, though, my question is how to bind that ng-model="item" to a data source updated by a service.
http://jsfiddle.net/whtevn/mUhPW/2/
Well, it looks like I've found a pretty satisfactory answer to this.
I exposed the storage object itself through the controller
function MyDisplayCtrl($scope, ItemStore) {
$scope.items = ItemStore.items;
$scope.item = ItemStore.currentItem;
// expose the itemstore service to the dom
$scope.store = ItemStore
$scope.getItem = function(){
return(ItemStore.currentItem);
}
}
and then address the currentItem directly
<div ng-controller="MyDisplayCtrl">
<select ng-model="store.currentItem" ng-options="i.name for i in items">
</select>
</div>
http://jsfiddle.net/whtevn/Cp2RJ/3/
Try using ng-options:
<div ng-controller="MyDisplayCtrl">
<select ng-options="i.name for i in items"></select>
</div>
See: http://docs.angularjs.org/api/ng.directive:select

Categories

Resources