I am trying to understand data binding in Angularjs.
What I want to do is establish binding between pages that is if I change the input on first.html, the data should automatically change in second.html.
For example,
This is first.html:
<div ng-controller="MyCtrl">
<input type="text" ng-model="value"/><br>
{{value}}
<input type="submit" value="Second page"/>
</div>
and say second.html has only this piece of code {{value}}.
and in the .js file we have $routeProvider which takes the template url as 'second.html' & the controller is 'MyCtrl'.
So the controller is:
MyApp.controller(function($scope){
$scope.value="somevalue";
})
By doing the above way the {{value}} on the second.html is getting the value "somevalue". Which is comming from the controller.
But if I change the input value dynamically that is on the first.html, the value on the second.html is not getting that value.
My question is how do I bind the value on second.html with first.html automatically.
To understand the question clearly, Suppose there is an input field for entering text and a submit button on first.html, then I want to get the Input value of the text field of the first.html on the second.html page on Submit.
Use a service and store your model there. Gloopy already has a good example of this here: https://stackoverflow.com/a/12009408/215945
Be sure to use an object property instead of a primitive type.
If you'd rather use $rootScope, then as above, define an object, rather than a primitive:
$rootScope.obj = { prop1: "somevalue" }`
then bind to that object property in your views:
<input type="text" ng-model="obj.prop1">
{{obj.prop1}}
If you attach your data to $rootScope if will survive transitions across controllers and be part of all $scopes (prototype inheritance magic)
//**attach in controller1:**
function MyCtrl1($rootScope) {
$rootScope.recs= { rec1 : "think philosophically" };
}
//**do nothing in controller for view2:**
function MyCtrl2($scope) {
//nothing
}
//**Markup for view2: automaticall makes use of data in $routeScope**
<p>Try doing this: {{recs.rec1 }}</p>
//**markup for view1 to respond to OPs question in comments**:
<input ng-model="recs.rec1" />
Update: Creating a custom service is a more scalable and structurally sound way to handle this, but the $rootScope method is the quick and dirty way.
Update2: added view1 markup to respond to OP question, edited example to take advantage of correct advice to use object rather than primitive.
Found the Solution to what I was looking for, The solution is in the Angular docs, here is the link http://docs.angularjs.org/cookbook/deeplinking.
Some part of the example on that link answers my question.
You should user $broadcast, $emit or scope communication. Try to avoid overloading the rootScope. It is as a bad practice as saving data into the application sessions.
Related
I currently have a partial HTML that is being routed to, with a template and a custom Controller. The code snippet in my Angular template I would like to get working is:
<input type="text" typeahead=val for val in getValue($viewValue)>
However, it never enters into the function getValue(), while all other functions in my controller seem to be okay. When I take the typeahead out of the Angular template/partial, it seems to work. Why is this and how do I fix it?
You need to have an ng-model attribute to use the typeahead directive from AngularUI, even if you don't need to bind it to anything.
Change your markup to similar to the following:
<input type="text" ng-model="typeaheadVal" typeahead="val for val in getValue($viewValue)">
First of all: I am absolutely new to AngularJS but worked on MVC-projects in other languages.
I try to bind a Property containing HTML.
This is the code:
HTML:
<div ng-controller="MyController">
<p>{{About}}</p>
</div>
JS:
.controller('MyController', ['$scope', function($scope) {
$scope.About="This is me<br/>and not you!"
}
Now the HTML is encoded which I do not want (the <br/> should result in line breaks)
I already tried <p ng-bind-html="About"></p> but that resulted in no output at all
You need to allow html in your text which Angular does not by default.
Plunker: http://plnkr.co/edit/K4KRCQi4Rpe99MJel5J2?p=preview
Angular Docs for $sce
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires
bindings in certain contexts to result in a value that is marked as
safe to use for that context. One example of such a context is binding
arbitrary html controlled by the user via ng-bind-html. We refer to
these contexts as privileged or SCE contexts.
<div ng-controller="htmlChar" ng-bind-html="about"></div>
<script>
angular.module("app",[])
.controller("htmlChar",function($scope, $sce){
$scope.about= $sce.trustAsHtml("This is me<br/>and not you!");
});
angular.bootstrap(document,["app"]);
</script>
You shoudln't need to insert html through model binding in AngularJS since the philosophy of the framework is to keep the HTML (page's structure and style) intact and only bind the data to be shown inside that HTML.
If you really need to bind HTML tags into your data you need to use the $sanitize service.
You have to use angular compile functionality here, go through the link to get more information angular compile
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?
I'm writing a simple AngularJS example that doesn't have a controller. It just uses the default global controller/model.
<!DOCTYPE html>
<html lang="en" ng-app=>
<body>
<input type="text" ng-model="firstName" placeholder="first name">
<input type="text" ng-model="lastName" placeholder="last name">
<br />
<h2 ng-style=style>Welcome {{firstName + ' ' + lastName}}</h2>
<button ng-disabled="!(firstName.length && lastName.length)">Sign Up</button>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
</body>
</html>
Where are the firstName and lastName values stored? This form works as expected so the two-way binding is working. I've tried looking through the window object and I didn't see anything in there that might be the global Angular controller. If I wanted to submit these values, where would the "handle" to them be in this example?
UPDATE
As I said, this is working as evidenced by this jsFiddle. The name is computed correctly and the button is only enabled once both firstName and lastName have values. I also tried using Batarang and it did not help. It told me that there wasn't a scope defined yet the application still functions.
Try installing Batarang and inspecting for yourself, though I believe those two values would be applied to $rootScope
You can view your scope using ng-inspector. It may not work in js-fiddle, because they do things with iframes that hide the global variables the inspector depends on.
I tried it on a test application with an unnamed module, as in your example, and it discovers the scope as $rootScope 002
Because of this I theorized, and have found through experiment, that the scope of an application without a declared module name (and probably with one, too) is attached to whatever DOM node the ng-app directive is on.
So, if you put ng-app on the html tag, this would get you your scope:
angular.element(
document.getElementsByTagName('html')[0]
).scope();
Using JSFiddle will complicate this testing, since it does iFrame stuff and has multiple html and body tags. Try it in an isolated environment and it's pretty straight-forward.
In console, select the result frame, and type:
angular.element($('body')).scope().firstName
You should see the firstName value. With regards to "If I wanted to submit these values" part, I believe you want to do an ajax call with these values. The best place to do that is by attaching a controller, where you will have direct access to these variables, and then you can use $http service to post to a server.
I am having troubles linking the inputs of my form into a defined factory that I have injected into the controller that renders the form. Here is my factory:
App.factory('DeviceSelection',function() {
var states=[{selection:{}},{selection:{}},{selection:{}},{selection:{}}];
return states;
});
And here is an input of my form:
<div class="controls">
<label class="radio">
<input type="radio" name="user[role]" id="user_role_managing_editor" value="Managing editor" ng-model='states[0].selection.hours'>
Yes
</label>
<label class="radio">
<input type="radio" name="user[role]" id="user_role_area_editor" value="Area editor", ng-model='states[0].selection.hours'>
No
</label>
</div>
So, when I try to click on that Radio box, I see the following in the JS Console:
TypeError: Cannot read property 'selection' of undefined
Does that mean that I need to initialize the model before the view is rendered. If so, where?
I am trying to achieve a multi-step form, linking all the inputs in the model, until last step is reached when I am able to send the results to an API. As asked here:
Store status between forms in AngularJS?
You say that you have injected in your controller. It would be nice to see that injection, but let me blind guess something that might be happening:
I am assuming you have (something like) this:
YourApp.controller('YourController', ['$scope', 'YourFactory', function ($scope,$yourFactory) {
...
But, have you set that injection into the $scope? Otherwise the view won't have access :)
So, if you don't have it, do this:
$scope.states=$yourFactory;
I really believe this is what happened. The controller needs to tell the view where to find that state array through the $scope