Use ng-model in nested Angularjs controller - javascript

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 ..//
})

Related

How to reference child controllers of a certain type from an angular directive or component?

When I define an angular component or directive, I can use 'require' to bind to a parent controller like require: {'parentForm' : '^^ngForm'}.
I'd like to do the same thing, but in reverse: require: {'childrenForms' : '[children]ngForm'} would bind childrenForms to an array of all controllers contained within my component which are ngForms.
I want to do this in order to build components that add aggregate behavior to directives I don't have control over. For example my-special-form container could have an isValid() method that returns true if all the ng-forms within it are valid at the moment.
Is there any way to do this? Am I making a mistake by even wanting to?
There is no option to require inner child directive in Angular. Personally I don't think so the approach you thought about would be good approach to go for, like here parent directive want to know directly about child directive. Rather I'd say choose the approach where child directive will pass required data to parent controller by calling one of its method.
If you only wanted to validate inner forms then you can wrap all the inner forms inside wrapper form ng-form with some name(you can have nested form in angular using ng-form directive). You can see example below, where you can see I wrapped all the inner form with one wrapper form element ng-form. So what happen is, when any one of the forms get invalid the parent form will invalid. If all forms are valid then parentForm will become valid as well.
Markup
{{parentForm.$valid}}
<div ng-form name="parentForm" my-directive>
<form name="form1" some-directive>
.....
</form>
<form name="form2" some-directive>
.....
</form>
<form name="form3" some-directive>
.....
</form>
</div>

Accessing ngModel elements that use a class

I have many elements in my HTML code that have their ngModel assignment defined as ng-model = "object.[something]".
For example:
<div class="form-group row" ng-model="object.askUser">
I do this to be clear of my purpose for these elements. My question is how do I access these element in my Javascript? Do I call $scope.object.askUser, $object.askUser, or something else? I had a hard time finding things on the web about this, most likely because I wasn't quite sure of the words to use in the search bar to describe what I am trying to do.
Inside your controller use $scope.object.askUser:
var app = angular.module('TestApp', []);
app.controller("testCtrl", function ($scope) {
$scope.someObject = {};
$scope.someObject.askUser = "Hello, world!";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="TestApp">
<div ng-controller="testCtrl">
<input ng-model="someObject.askUser" />
</div>
</div>
Side note:
You use in your example <div> with ngModel.
ngModel Docs:
The ngModel directive binds an input,select, textarea (or custom form
control) to a property on the scope
If you want to one-way bind a model to a div use Angular Expression:
<div class="form-group row">
{{ object.askUser }}
</div>

ng-click doesn't take parameters from the DOM

I have the following code:
<input id="id">
<button data-action="bea" ng-click="Create($('#id1')[0].value);" class="btn">Insert ID</button>
<button data-action="bea" ng-click="Create($('#id2')[0].value);" class="btn">Insert ID</button>
In the JS I have:
$scope.Create = function (id){
if (id === undefined) {
$scope.data = "You must specify an id";
} else {
$scope.data = data;
console.log(data);
});
}
};
When the call gets into the Create function the value of the id is undefined.
If I add the following line at the beginging of the Create function everything works ok:
id = $('#id')[0].value;
If I send a constant value it works:
<button data-action="bea" ng-click="Create('SomeID');" class="btn">Insert ID</button>
Why is this happening and how can I do that without putting the line of value into the method?
Thanks
This is just an extension of comments and other answers, You could achieve this in many ways using angular, one simple example could be:-
<!-- Add a controller -->
<div ng-controller="MainCtrl">
<!-- Give a model binding to your text input -->
<input ng-model="userEntry" type="text"/>
<!-- ng-click pass which ever argument you need to pass, provided it is an expression that can be evaluated against the scope or any constants -->
<button data-action="bea" ng-click="Create(userEntry);" class="btn">Insert ID</button>
<!-- Some simple data binding using interpolation -->
{{data}}
<!-- Just for demo on repeater on a list of items on the scope -->
<div ng-repeat="item in items track by $index">{{item}}</div>
</div>
Example Demo
My 2 cents on the lines of what were originally trying to do:-
Use angular bindings instead of accessing DOM directly for getting the data, it really helps you deal with just the data without worrying about how to access or render it in DOM. If you think you need to access DOM for implementing business logic re-think on the design, if you really need to do it, do it in a directive. Angular is very opinionated on the design and when where you do DOM access.
ng-model
ng-binding
controller
all about ngmodel controller
This is not the way you should do in AngularJS. You should really think in Angular if you want to use AngularJS. Refer this post ("Thinking in AngularJS" if I have a jQuery background?)
All DOM manipulation should be done in Directive. Refer this page that I found really clear.
(http://ng-learn.org/2014/01/Dom-Manipulations/)
My guess is that $ is not bound to the jQuery function when the ng-click value is evaluated, because it is not exposed in the Angular scope.
Solutions to adress this:
expose the jQuery function in scope somewhere, e.g $scope.$ = $; in a controller.
make the Create function parameterless as you suggested, with a var id = $('#id')[0].value; at the beginning
my favorite : avoid using jQuery. If you put some data in the #id element, there's probably a more natural and AngularJS-idiomatic way of retrieving it than querying the DOM (e.g an Angular service).
In particular, if the element you're targeting is an <input> element, then use the ngModel directive to link the value to a $scopeproperty that will be accessible in the controller :
<input ng-model="inputData"/>
The JavaScript you are trying to pass as a parameter of the create function is not available in the scope of the Create function.
Try to target the element a different way.
Does that help?

AngularJS Passing Scope?

I'm actually not sure what the title of the question should be, as it's not clear to me what I am missing.
I have boiled this down to a very simple example (the actual case is more complex). I have a text box and button inside of an ng-switch. The switch, I've read, creates it's own local scope.
What I want to do pass the value of the text box to a function when the button is clicked. In the function, I will do what needs to be done with the value, then clear the text box. I'm struggling to find the right way to do this.
Controller Code:
$scope.temp = 1;
$scope.tempCall = function (tempModel) {
tempModel = ""; //this doesn't work
$scope.tempModel = ""; //nor does this
};
HTML/Template:
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel" />
<input type="button" ng-click="tempCall(tempModel)" />
</div>
<div ng-switch-when="2">TWO</div>
</div>
I believe I can actually traverse the scope from the parent or root scope and clear the value, but that doesn't "feel" correct. What is the correct (Angular) way to clear this value?
When you are working with primitive values in angular scopes, you cannot overwrite a value in a parent scope from a child scope. This is because angular uses javascript prototypal inheritance.
What you could do in this case is create an object in the parent scope, then you can update the values on that in the child scope. Because you are not overwriting the object (only properties attached to it) the references work.
I created a demo of this on plunk you can view it here
$scope.temp = 1;
$scope.tempModel = {};
$scope.tempCall = function () {
$scope.tempModel.previous = $scope.tempModel.value
$scope.tempModel.value = "";
};
<div ng-switch on="temp">
<div ng-switch-when="1">
<input ng-model="tempModel.value" />
<input type="button" ng-click="tempCall()" />
{{tempModel.previous}}
</div>
<div ng-switch-when="2">TWO</div>
Here's one way to do it:
<input type="button" ng-click="tempCall(tempModel);tempModel='';" />
Probably the more "Angular way" would be to use a dot in your model like:
<input type="text" ng-model="tempModel.value" />
Then call your function by passing the tempModel object like:
<input type="button" ng-click="tempCall(tempModel)" />
Then you will be able to clear the value with:
$scope.tempCall = function (tempModel) {
tempModel.value = "";
};
Here is a fiddle
To prevent databinding issues, "the rule of thumb is, if you use ng-model there has to be a dot somewhere." Miško Hevery

Accessing the model inside a ng-repeat

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)"

Categories

Resources