Why can't I do this in Angular.js:
document.getElementById('divid').value = 'Change Text to This';
And what is the "right" (Angular) way of doing it?
In Angular you use the ng-model directive in order to create a two-way data binding between your model (i.e. a JS variable) and the view (i.e. the <div>). Basically, this means that whenever you change the data in the view (through an input, for instance), the change will be reflected in your JS variable. See below:
HTML:
<html ng-app="myApp">
<div ng-controller="MyCtrl">
<div>{{myVariable}}</div>
<input type="text" ng-model="myVariable" />
</div>
</html>
JS:
/* App global module */
var myApp = angular.module('myApp');
/* Define controller to process data from your view */
myApp.controller('MyCtrl', function($scope) {
$scope.myVariable = "initialValue"; // this is the variable that corresponds to text inserted in your input
});
Here, myVariable will have "initialValue" as an initial value. Any further changes to the input will overwrite the value of this variable.
Also notice that {{myVariable}} injects the variable the data into your div. When you change the value in the input, the div text will be changed as well.
You'd have to bind a controller to your mark up and initialise your Angular app.
<div ng-app="myApp">
<div id="divid" ng-controller="valueController">{{value}}</div>
</div>
Then you can simply define a scope variable in your controller
myApp.controller("valueController", function($scope) {
$scope.value = "Hi!";
});
It is considered best to use the ng-app directive in the HTML tag of the page
jsFiddle
Related
I have the following code.
html:
<body ng-controller="MainCtrl">
<div ng-if="isOwner">
<input type="checkbox" ng-model="checkboxClicked"
/>
</div>
<span ng-show="checkboxClicked">Non Editable</span>
<span ng-hide="checkboxClicked">Editable</span>
</body>
js:
app.controller('MainCtrl', function($scope) {
$scope.isOwner="true";
$scope.checkboxClicked="true";
});
If Owner and checkboxClicked values are true, then checkbox should be always selected by default on execution i.e with Non-Editable.
like:
It should execute the same above output by default even though if we refresh the browser also (here also if Owner and checkboxClicked values are true).
As a Owner, we can uncheck this checkbox also, so then output should be with the Editable checkbox i.e, like: Editable.
Please help me in this context to get my desired outputs as per above screenshots and conditions, I have tried with that code, but it is giving with empty checkbox with Non Editable text, as I believe I am failing to write the conditions.
Created Plnkr.
There is some issue with AngularJS when you bind a variable directly to the $scope:
https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU
To fix this, you have to create an additional object which wraps the data in the $scope which are available in the template:
app.controller('MainCtrl', function($scope) {
$scope.data = {
isOwner: false,
checkboxClicked: false
};
});
And change the template accordingly:
<div ng-if="data.isOwner">
<input
type="checkbox"
ng-model="data.checkboxClicked"/>
</div>
...
I am exploring AngularJS1 and found something strange, please help me to find how name is working for both ng-bind and ng-model here.
Output is coming as :John Doe but it is working for same variable name with bind and model there it is confusing me.Please help me to understand.
<div ng-app="myApp" ng-controller="myCtrl">
<input ng-model="name">
<h1>{{name}}</h1><br>
<p ng-bind="name"></p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.name = "John Doe";
});
</script>
They are all the same variable. You have $scope.name and you're telling ng-bind and ng-model to use $scope.name;
ng-model="name" <-- Angular looks on the scope object for a property called name. If it's there it uses it, if it's not, it'll create it.
ng-bind="name" <-- Angular looks on the scope for a property called name. Then uses that value.
Angular created a scope object for the div with ng-controller
<div ng-app="myApp" ng-controller="myCtrl">
<input ng-model="name">
<h1>{{name}}</h1><br>
<p ng-bind="name"></p>
</div>
All directives with-in that div's hierarchy can access the scope object.
If you Google "Understanding Angular scopes" or something similar you'll get a lot of articles on it.
http://blog.carbonfive.com/2014/02/11/angularjs-scopes-an-introduction/
I have the following code (see below) in whichI use ng-include. The ng-model="numLines" creates a binding of the value in the box and the function changeNumLines() specified in ng-change is called every time the value inside the input box changes. The value of the $scope.numLines inside the changeNumLines() is supposed to be the new changed value. However, it is not. The value that I output to the console is always "1" no matter what input is typed in the box.
However, if I do not use ng-include and just copy paste the partial html file: structCustomRows.htm into index.html instead of ng-include line everything works fine.
So, why is this happening with ng-include and how can I get around it?
Thanks.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<base href="/">
</head>
<script>
var app = angular.module('parserUI', []);
app.controller('CustomRowsCtrl', ['$scope', function($scope) {
$scope.numLines = 1;
$scope.changeNumLines = function() {
console.log("DEBUG: changeNumLines()");
console.log(String($scope.numLines));
}
}]);
</script>
<body ng-app="parserUI">
<h2>Header</h2>
<div ng-controller="CustomRowsCtrl">
<div ng-include src="'app/partials/structCustomRows.htm'"></div>
</div> <!-- ng-controller="CustomRowsCtrl" -->
</body>
</html>
structCustomRows.htm
<input type="text" ng-model="numLines" ng-change="changeNumLines()">
Looking at the docs, it says that "This directive creates new scope". Meaning the $scope.numLines in your controller is actually in the parent scope of your ngInclude directive.
The simplest way to fix this is to put the controller definition in the ngInclude to make it all the same scope. Otherwise, you will have to access the parent scope using something like $scope.$parent.numLines.
When you use ng-include, Angular creates a new scope, causing your variable to be overwritten to the new scope, instead of the one you wanted. As the new scope is an instance of the original scope (the one you want), you can create an object on CustomRowsCtrl; the objects are copied to the new scope as a reference, enabling you to share the same object in between child and parent scope.
Obs.: You can also use $parent, as suggested on the link below, but using pointers is a lot cleaner and if you use multiple nesting, you won't need to use $parent.$parent and so on.
Example:
On the controller:
$scope.selection = {}
On the HTML:
ng-model="selection.numLines"
More about ng-include scope:
AngularJS - losing scope when using ng-include
It's all about scope creation in Angular.
The directive ng-include create a new scope and you've defined the numLines in the parent scope, i.e the scope of the controller.
If you want to see the changes in your parent scope, you'll have either to write ng-model="$parent.numLines" in the included Html template or simply use the onload attribute of the ng-include directive : onload="numLines = numLines"
ng-include directive creates its new scope, There is so many work round for tackle this problem.
Create your own directive of static include which does not creates its own scope. for example.
app.directive('staticInclude', ['$http', '$templateCache', '$compile', function ($http, $templateCache, $compile) {
return function (scope, element, attrs) {
var templatePath = attrs.staticInclude;
$http.get(templatePath, { cache: $templateCache }).success(function (response) {
var contents = $('<div/>').html(response).contents();
element.html(contents);
$compile(contents)(scope);
});
};
}]);
so you can use this directive, its not create own scope.
Your html looks like
<body ng-app="parserUI">
<h2>Header</h2>
<div ng-controller="CustomRowsCtrl">
<div static-include=="app/partials/structCustomRows.htm"></div>
</div> <!-- ng-controller="CustomRowsCtrl" -->
</body>
You include controller in template means your file 'app/partials/structCustomRows.htm' has main div which initialize its relevant controller.
I have a little widget I'd like to use over and over on a single page. It has its own controller. Problem is it needs a piece of data to operate (basically a key), and each key is contained in the parent controller.
Here is an example (which is obviously wrong)
http://plnkr.co/edit/VajgOr1LqpLDnbEJcvor?p=preview
script:
angular.module('myApp', [])
.controller('ParentCtrl', ['$scope',
function($scope) {
$scope.keyForChartABC = "somekey1";
$scope.keyForChartXYZ = "somekey2";
$scope.keyForChartLALA = "somekey3";
}
])
.controller('ChartCtrl', ['$scope',
function($scope) {
//todo: have $scope.key assigned from parent somehow
//not shown: use $scope.key to pull data and format chart data
}
])
index:
<!-- ng-init like this is quite wrong -->
<div ng-init="key = keyForChartABC"
ng-include="'chartwidget.html'"></div>
<hr>
<div ng-init="key = keyForChartXYZ"
ng-include="'chartwidget.html'"></div>
<hr>
<div ng-init="key = keyForChartLALA"
ng-include="'chartwidget.html'"></div>
chartwidget:
<div ng-controller="ChartCtrl">
<p>Drawing chart for data: {{key}}</p>
<p>some chart directive here</p>
</div>
As you can see in the plunker, what I tried here with ng-init doesn't work - key for all the sub-controllers end up with the same value.
I've gotten this to work with ng-repeat and an array of data in the parent, somehow $index gets set in each child to the right index and stays that one value. But I'd like to avoid using ng-repeat in this case so I can have more control of the layout.
Creating re-usable widgets is exactly the purpose of Directives. You can create a directive which handles the output of your widget quite easily.
I forked your plunker and modified it to change it to use a directive.
Here are a few highlights:
First, your template no longer needs the controller defined within it.
<div>
<p>Drawing chart for data: {{key}}</p>
<p>some chart directive here</p>
</div>
Next, the directive is defined, with an isolate scope which is unique to each instance of the directive:
.directive('chartWidget', function(){
return {
restrict: 'E',
scope: {
key: '='
},
templateUrl : 'chartwidget.html'
}
})
Lastly, the directive is declared in the HTML. Note the camel-case name of the directive in the JavaScript, but the hyphenated name in the HTML:
<div>
<chart-widget key="keyForChartABC"></chart-widget>
<hr>
<chart-widget key="keyForChartXYZ"></chart-widget>
<hr>
<chart-widget key="keyForChartLALA"></chart-widget>
</div>
Edit
I updated the plunker to show binding the directive property to an inner controller. This method uses the ControllerAs syntax to define the controller, and binds the directive's scope to the controller scope.
Relevant changes:
.directive('chartWidget', function(){
return {
restrict: 'E',
scope: {
key: '='
},
templateUrl : 'chartwidget.html',
controller: 'chartWidgetController',
controllerAs: 'ctrl',
bindToController: true
}
})
.controller('chartWidgetController', function(){
console.log(this.key);
})
And a small change to the template to support ControllerAs:
<div>
<p>Drawing chart for data: {{ctrl.key}}</p>
<p>some chart directive here</p>
</div>
Note that trying to use ng-controller= in the template will cause the template to have a different scope object from the scope object created for the directive, and the controller would not have access to the properties defined on the directive.
Also note, bindToController is a feature of angular 1.3.x or higher. in angular 1.2.x or earlier, your only option was to use $scope.$watch to monitor the isolate scope for changes.
here is my testing page :
<div ng-controller="test">
<input ng-keyup="asIwrite($event)" />
<p id="entityContent"></p>
</div>
and my controller :
EntitiesApp.controller('test', ['$scope', function ($scope) {
$scope.asIwrite = function ($event) {
$('#entityContent').html($event.srcElement.value);
}
}]);
this is actually working, if i write click in the input, the paragraph will hold the clickable url (processed html).
I am using jQuery to update the content of the paragraph as to show html element as they render in the page..
But using jQuery is a work-around in my opinion.
I want to achieve that using just Angular. How can I do ?
note : sure I can sweep jQuery off my project and use innerHTML of the
element but I want to know the way of doing that in Angular with
bindings. I used ng-bind on a paragraph element but that just
render the value of the textarea as is, no html process is performed.
See working example below.
You are right by doubting using jQuery is the right thing to do, and as you would expect it is not. The angular way to do that is register your input into the scope using ng-model, and the way to display it is using the ng-bind-html directive. (or simply ng-bind if it was simple text with no HTML)
However, Angular will not allow HTML binding by default as it could be a security issue. If you are sure about what you write, you can use $scope.trustAsHtml as showed in my example.
angular.module('test', [])
.controller('test', ['$scope', '$sce', function ($scope, $sce) {
$scope.trust = function(content) {
return $sce.trustAsHtml(content);
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="test">
<input ng-model="content"/>
<p ng-bind-html="trust(content)"></p>
</div>
You probably have tried to do something like this but the content doesn't come out as html
<input ng-model="input" />
<p id="entityContent" ng-bind-html="input"></p>
You need to ensure strict context escaping as described here:
https://docs.angularjs.org/api/ng/service/$sce
Please keep in mind what you're saying you want to do is explicitly prevented by angular developers as a way to mitigate XSS attacks
You don't need to do that, angular is simplier than that.
<div ng-controller="test">
<input ng-model="variable1" />
<p id="entityContent">{{variable1}}</p>
</div>
Angular binds variables automatically. When the input's value change, the new value will be printed.