I have a template which I want to use in many parts of my application.
The template contains select box with a model assigned.
I include the template by the means of ng-include.
<span ng-include="'templateWorking'" ng-init="selectModel=data.field"></span>
and then in template:
<script type="text/ng-template" id="templateWorking">
<select ng-model="selectModel">
<option value="Test1">Test1</option>
<option value="Test2">Test2</option>
</select>
Of course, it does not work since ng-include creates a new child scope.
It is possible to get it work when I use one model (using dot . in a model like data.model).
But how it is possible in this particular case so I can use this template with different models in different controllers?
Besides, I need to dynamically attach a handler to the select (e.g. ng-change="doSmth()").
Thanks in advance.
For the reference:
http://plnkr.co/edit/NiLQyVQGb6X1mA0sVvA1?p=preview
In this case it was best to use a directive instead. You can get some control over ng-include by using onload but if that's not enough, using a directive is your best bet.
Reference: Difference between onLoad and ng-init in angular
Related
This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 5 years ago.
I have a general template for all pages which contains a menu bar and it is outside the ng-view.From one of my page which is inside the ng-view i want to bind input data to this template area(this area is under a different controller than the input page).I mean when i will enter name,the name will appear to the template area.Is it possible ?
Here is the plunker
<body ng-app="sampleApp">
<div class="container">
<div class="row">
name is :{{name}}<br/>
username is :{{uname}}
<div class="col-md-3">
<ul class="nav">
<li> Add name </li>
<li> add username </li>
</ul>
</div>
<div class="col-md-9">
<div ng-view></div>
</div>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="app.js"></script>
</body>
This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models – watch 3 minutes worth. Misko demonstrates the primitive binding issue with ng-switch.
Having a '.' in your models will ensure that prototypal inheritance is in play. So, use
<input type="text" ng-model="someObj.prop1"> rather than
<input type="text" ng-model="prop1">.
— AngularJS Wiki - What are the nuances of scope prototypal / prototypical inheritance?
The DEMO on PLNKR
$scope.obj is working like a $rootScope variable. Is it for prototypal inheritance?
Scopes are arranged in hierarchical structure which mimic the DOM structure of the application. Each AngularJS application has exactly one root scope, but may have any number of child scopes.
ng-app --> $rootScope
|- ng-controller --> $scope (container)
|- ng-view --> $scope (view)
By using: <input ng-model="obj.name" /> the ng-model directive in the view controller uses prototypical inheritance to find $scope.obj from outside the view. It can then get and set the name property of that object.
For more information, see AngularJS Developer Guide - Scope Hierarchies
$rootScope exists, but it can be used for evil
Scopes in AngularJS form a hierarchy, prototypically inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
— AngularJS FAQ - $rootScope exists, but it can be used for evil
Angular's $rootScope can be used to share information between the app's components (besides other uses). It is discouraged to rely upon it too much because it could become polluted or difficult to trace up and down the app's entire scope 'stack'. But if you really need or want to set 'global' data, it works:
In your new plunkr, you are using both ng-model and ng-value for the text input. Remove the ng-value altogether. (It is used typically for elements that have 'value' properties, like radio buttons and checkboxes, where the 'value' is 'checked' or 'selected', etc.) ng-model is what you want.
http://plnkr.co/edit/DnzOdRicXLHtg4DqoVdJ?p=preview
name is :{{$root.name}}
username is :{{$root.uname}}
and
Name: <input ng-model="$root.name">
<h1>You entered: {{$root.name}}</h1>
I would like to save an object in a ngRepeat so that I can use that object in its children, like shown in this code:
<div ng-repeat="bar in foo.bar>
<div ng-repeat="qux in baz.qux" myvalue="{'item1':foo.var1, 'item2':qux.var2}">
<div ng-click="myFirstFunction(myvalue)"></div>
<div ng-click="mySecondFunction(myvalue)"></div>
</div
</div
The object I want to generate and then use is rather large and I'd rather not define it repeatedly for each ngClick directive.
I considered saving it into a scope variable but the object will change for each iteration of the ngRepeat.
Is there a directive or an other way that I can use to store this value for later use?
To avoid the repetition of what is probably a long variable definition, you can use the ngInit directive, whose content will be executed each time a corresponding element is created.
<div ng-repeat="bar in foo.bar>
<div
ng-repeat="qux in baz.qux"
ng-init="myValue = {'item1':foo.var1, 'item2':qux.var2 }"
>
<div ng-click="myFirstFunction(myValue)"></div>
<div ng-click="mySecondFunction(myValue)"></div>
</div>
</div>
However, a complex code in a template is rarely a good idea. Contemplate moving your logic inside a controller, as advised by the documentation:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
You can just do the naive thing here and it'll work:
<div ng-repeat="bar in foo.bar>
<div ng-repeat="qux in baz.qux">
<div ng-click="myFirstFunction(foo, quz)"></div>
<div ng-click="mySecondFunction(foo, quz)"></div>
</div>
</div>
Angular will know the scope of the repeat when you click.
You could store it in local storage using ng-storage.
https://github.com/gsklee/ngStorage
This would allow you to store it, then use it anywhere in the application.
cookies, you also have ng-cookies
https://docs.angularjs.org/api/ngCookies
try this out! or cookieStorage
I have an html file with ng-includes inside
<div ng-controller="MapMenuCtrl">
<div class="mapMenu row">
<ng-include src="'partials/mapMenu/filterDropdown.html'"></ng-include>
<ng-include src="'partials/mapMenu/alertDropdown.html'"></ng-include>
<ng-include src="'partials/mapMenu/investigationDropdown.html'"></ng-include>
</div>
</div>
The problem is that I need MapMenuCtrl for each of ng-include. But when it is set as in example, it works, but only a half. For example in one of this files I use ng-model for one of $scope variables of MapMenuCtrl and it doesn't bind.
I was trying to set controller for each of ng-include, but it loads 3 times, though I need only 1.
I hope you understood me. I know, that my english is quite bad
ng-include creates a new scope. Put an object on the controller scope and put all bindable stuf inside.
You can call it model for example. Then the bindings should work as expected.
Here is a link for a details of the problem you face i believe:
Does my ng-model really need to have a dot to avoid child $scope problems?
I have a table that I'm including on different pages, this works great except I can't get to the values in the included table. If I use this on a page:
<div data-ng-include="'/app/views/tasks/tasksTable.html'" />
the table shows up but I can't display the value in the file tasksTable.html, this shows undefinded:
<td>
<i class="icon-ok-sign" ng-click="addTask()"></i>
</td>
<td>
<input ng-model="task" />
</td>
From the controller:
$scope.addTask = function (data) {
console.log($scope.task);
};
If I put the table in my file instead of using ng-include to display the table I can display whatever I type into the input tied to ng-model="task".
The reason why you can't access the task is due to two reasons. Firstly, is because ng-include creates a new scope for the template that is a child of the parent controller scope. The second reason is that you are attaching your string model directly to the scope and not creating an object that contains your model. I created a working CodePen example to demonstrate how to solve your problem.
You should read up on prototypical inheritance and how it affects on scopes.
I hope this helps.
I want to bind tag name to variable in AngularJs. Direct way doesn't work:
<div ng-app ng-init="list=['pre', 'div', 'em']">
Check the list: {{list}}
<div data-ng-repeat="item in list">
{{item}}: <{{item}}>content</{{item}}>
</div>
</div>
How to do it right?
You're going to want to make a Directive and use the $compile service module.
Angular template system works on DOM tree, not on strings, so template must be valid HTML and usage of {{}} for tagname is impossible. We can write own directive for it (see Max answer) or if here is small set of options it can be more easy to use ng-include and set of templates for options.