I have a ng-repeat loop over processes. What I am trying to do is to add a new block to the current process via a form with select box. However, my problem is I cannot access the model inside the loop from the controller. I guess this is because a new scope is created in a ng-repeat loop.
Still I couldn't find a way to access model from controller. Here is html and javascript code pieces for you to understand problem better.
<div class="container" ng-controller="ProcessCtrl">
<div class="process" ng-repeat="process in processes">
<form class="form-inline" ng-submit="addBlock($index)">
<select ng-model="blockType">
<option value="1">type1</option>
<option value="2">type2</option>
<option value="3">type3</option>
</select>
<button type="submit">add</button>
</form>
</div>
</div>
angularjs controller
function ProcessCtrl($scope, $filter) {
//...
$scope.addBlock = function(index) {
alert($scope.blockType); // undefined
$scope.processes[index].blocks.push({type: $scope.blockType});
};
}
Yes, the problem is that the parent scope can not access the child scopes created by ng-repeat.
Modify addBlock to also pass up the blockType:
ng-submit="addBlock($index, blockType)"
Related
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).
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()">
I have two nested controller in angularjs, and want to use ng-model from outer in inner controller. Suppose this
<div ng-controller='outController'>
// data.Name : from outer controller
<div ng-controller='innerController'>
<input type="text" ng-model='name' ng-init='name=data.Name'>
{{data.Name}} // display this scope value
</div>
</div>
data.Name value display in html page but not bind to name ng-model.
How to bind this value to inner ng-model?
You should follow dot rule in this case, so that will allow you to access the parent scope inside the child scope using prototypal inheritance. For using this approach you need to have an object declared in your parent controller like here it should be declared in outController then the inner controller will not create a new one, it will use the existing one using prototypal inheritance
Markup
<div ng-controller='outController'>
// data.Name : from outer controller
<div ng-controller='innerController'>
<input type="text" ng-model='data.Name'>
</div>
</div>
Code
app.controller('outController', function($scope){
$scope.data = {};
//..other code here ..//
})
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:... " >
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