I am trying to get up to AngularJS directives and scope bindings. I will rather give my code and then ask question :
Here is my directive definition :
'use strict';
(function(){
var app = angular.module('gemStore', []);
var gem = {name:"Pearl",price:22.5 };
app.controller("StoreController",function(){
var self = this;
self.product = gem;
self.validateOnSubmit="myForm";
});
app.directive("requireOnSubmit",function(){
var directiveDefinitionObject = {
restrict:'A',
scope : {
validationFlag : '='
},
link : function(scope,ele,attr){
console.log(scope.validationFlag);
},
controller : "StoreController",
controllerAs : "store",
bindToController : true
};
return directiveDefinitionObject;
});}());
And Here is my html :
<!DOCTYPE html>
<html ng-app="gemStore">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body ng-controller="StoreController as store">
<div>
<h3>{{store.product.name}} </h3> <h3>{{store.product.price}} </h3>
</div>
<form name="myForm">
<input type="text" name="test" require-on-submit />
</form>
</body>
<script type="text/javascript" src="resources/js/angular.min.js"></script>
<script type="text/javascript" src="app.js"></script>
Now I want to bind validationOnSubmit property on controller with validationFlag and it should be two-way binding.
I have tried adding
<input type="text" name="test" require-on-submit validationFlag="validationOnSubmit"/>
and in directive :
scope : {
validationFlag : '=validationFlag'
}
But doesn't work. How to achieve this?
I'm not sure if 2 way binding works with controller properies but the correct syntax would be
validationFlag="store.validationOnSubmit"
The StoreController will be initialized twice. Once on the body element and once with the directive. To avoid confusion you should remove the controller from the directive and if you need access to the controller use the require propery.
Related
I have a simple directive with transcluded html.
I want to be able to inject directive scope params to the transclude.
I wrote a simple example in plunker :
https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
I know in angular 4 it can be done, but I can't find a good way to do it in angularjs.
// Code goes here
var app = angular.module("app", []);
app.controller("mainCtrl", function($scope) {
$scope.users = ["tal", "oren", "orel", "shluki"];
$scope.deleteUser = (user) => {alert("trying to delete", user);}
});
app.directive('myList', function myList() {
return {
restrict: 'E',
transclude: true,
template: "<div><table><tr ng-repeat='item in collection'><td> This is inside myList - user name: {{item}} <ng-transclude></ng-transclude></td></tr></table></div>",
scope: {
collection: "="
},
replace: true
};
});
<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs#1.6.2" data-semver="1.6.2" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="mainCtrl">
<h1>Hello Plunker!</h1>
<my-list collection="users">
<h2>This is transclude</h2>
<button ng-click="deleteUser(user)">Delete user: {{user ? user : "User name should be here"}}</button>
</my-list>
</body>
</html>
Will really appreicate some help.
plunker: https://plnkr.co/edit/jqyiQdgQxbeTrzyidZYF?p=preview
Here's a working plunker with your example.
http://plnkr.co/edit/BjSowyQdLXd0xoCZFqZ6?p=preview
The idea is to pass it as contents and not html as string. $compile is here because the link is done after ng-repeats already has transcluded its own template.
var template = '<h1>I am foo</h1>\
<div ng-repeat="item in users">\
<placeholder></placeholder>\
<hr>\
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent) {
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate) {
element.append(clonedTemplate);
});
});
If you want a proper explanation of what the problem was you should check the detailed answer here : Pass data to transcluded element
Hope this helped you out
<html>
<head>
<title>
</title>
<script src="../../angular.min.js"></script>
<script type="text/javascript">
myApp = angular.module('myApp', []);
myApp.controller("empController", function($scope){
$scope.ename = {nm : "Harry"};
$scope.changeName = function(){$scope.ename.nm = "Ron";};
});
myApp.directive("empDirective", function(){
return {
scope : {employeeName : "=myEmpName", nameChange : "&click"},
template : 'Employee Name is {{employeeName.nm}}. <button ng-click="nameChange()">Change Name</button>'
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="empController">
<div emp-directive myEmpName="ename" click="changeName()" > </div>
{{ename.nm}}
</div>
</body>
When I am running the above code I am not getting the employeeName.nm value inside directive. Not sure what I am missing. I am new in AngularJS
In your template, change
myEmpName
to
my-emp-name
Angular requires hyphen separated attributes in templates and converts them to camel case itself via a process called normalisation.
I got an index.html page with the following code
<html>
<head>
<title>{{title}}</title>
</head>
</html>
And i got a view.html
<div ng-controller="changeCtrl">
<input type="text" ng-model="page-title">
</div>
The routing works perfectly,
Now how can i bind the page-title model to the {{title}} while i type?
Thanks
To avoid using $rootScope or moving ng-app, use a service to handle setting the page title. In the snippet below I've given an example of using a service.
angular.module('app', [])
.service('PageService', function($window) {
return {
setTitle: function (newTitle) { $window.document.title = newTitle; }
};
})
.controller('ChangeCtrl', function(PageService) {
this.setPageTitle = PageService.setTitle;
});
<html>
<head>
<title>My Awesome App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="ChangeCtrl as ctrl">
<label>{{ctrl.title}}</label>
<input type="text" ng-model="ctrl.title" ng-change="ctrl.setPageTitle(ctrl.title)">
</div>
</body>
</html>
First of all, since the expression is right under the html root element, the angular application must "cover" this element. So ng-app should be on the html element:
<html ng-app="app">
Second, since the expression is outside of any controller scope, angular looks for the title field in the $rootScope. So, you need your input field, inside a view handled by a controller, to modify the value of a $rootScope attribute.
That can't be done:
<input ng-model="title" />
will set the field titleon the controller scope. What can be done, though, is to access an object, by scope inheritance, defined in the root scope, and modify one of its attributes. So, firstmake sure such an object exists in the root scope:
angular.module('app').run(function($rootScope) {
$rootScope.page = {
title: 'default title'
};
});
Then change the expressions to access the title attribute of this object:
<title>{{ page.title }}</title>
and in the controller view:
<input ng-model="page.title" />
make all your data bindings inside ng-controllers scope, that is {{title}} should inside or you move to your ng-controller to html tag, :)
I created a custom directive name kid. In that I have one input field with having usermodel object. I need to get its value in my controller. Can we get user model object in my controller. Actually I used to same directive in my view. I need to get both directive input values in my controller .
Here is my Plnkr
var app =angular.module('Testappp',[]);
app.controller('testcontroller',function(){
})
app.directive('kid',function(){
return {
restrict:"E",
scope:{},
template:"<input type='text' ng-model='usermodel'/>{{usermodel}}",
}
})
I updated your plunkr: updatedMyPlunker
I am passing the usermodel to the kid directive via its isolated scope.
The = sign makes sure that the two models will update through two way data binding
<body ng-app="Testappp">
<div ng-controller="testcontroller">
<kid usermodel="usermodel"></kid>
<kid usermodel="usermodelSecondKid"></kid>
</div>
</body>
var app =angular.module('Testappp',[]);
app.controller('testcontroller',function($scope){
$scope.usermodel = '';
$scope.usermodelSecondKid = '';
$scope.$watch("usermodel", function(newvalue,oldvalue){
console.log(newvalue);
})
})
app.directive('kid',function(){
return {
restrict:"E",
scope:{ usermodel: "=usermodel"
},
template:"<input type='text' ng-model='usermodel'/>{{usermodel}}",
}
})
Forked your plnkr. Passed two way data model from controller to directive. kid1 and kid2 are controller variable. Which will value you enter in text box.
<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs#*" data-semver="2.0.0" src="scruipt"></script>
<link rel="stylesheet" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
</head>
<body ng-app="Testappp">
<div ng-controller="testcontroller">
<kid ng-model="kid1"></kid>
<kid ng-model="kid2"></kid>
</div>
</body>
<script>
var app =angular.module('Testappp',[]);
app.controller('testcontroller',function(){
})
app.directive('kid',function(){
return {
restrict:"E",
scope:{
ngModel: '=ngModel'
},
template:"<input type='text' ng-model='ngModel'/>{{ngModel}}",
}
})
</script>
</html>
When I edit a value through an input field that is bound (perhaps bound isn't the right term) to a parent controller's scope, it seems to re-bind to the child controller's scope. This eliminates my ability to affect the value with functions built into the parent scope (clicking the button in the example) which works BEFORE I edit the input field manually.
E.g:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-example85-production</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0-beta.1/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0-beta.1/angular-animate.js"></script>
<script type="text/javascript">
angular.element(document.getElementsByTagName('head')).append(angular.element('<base href="' + window.location.pathname + '" />'));
</script>
</head>
<body ng-app="inputExample">
<script>
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.val = '1';
$scope.$watch('val',function(){
alert($scope.val);
});
$scope.set_val = function(){
$scope.val = 2;
}
}])
.controller('childController',['$scope', function($scope){}]);
</script>
<form name="testForm" ng-controller="ExampleController">
<div ng-controller="childController">
<input ng-model="val" />
<input type="button" ng-click="set_val()" value="change value"/>
</div>
</form>
</body>
</html>
http://plnkr.co/edit/cMz9dIMgnyImxQ0va7Wn?p=preview
childController creates a new scope that prototypically inherits from the ExampleController scope. Angular's use of prototypical inheritance and scope can be confusing, especially if you assume that prototypical inheritance behaves as inheritance does in other languages (C#, Java, etc).
If ExampleController.scope.val = 2, then the input will be initialized with the value 2, however, when the input modifies the value, it does so by setting
childController.val = 2.
Now both ExampleController.scope and childController.scope have a property val with a value of 2, but they are completely separate and not bound together.
This is why angular recommends using "dot notation" for models.
However, your childController looks to be unnecessary in your example and removing it will fix your problem. If you can't remove it (because your actual implementation is doing something with it, then change your models to "dot" notation.
<body ng-app="inputExample">
<script>
angular.module('inputExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.data = {};
$scope.data.val = '1';
$scope.$watch('data.val',function(){
alert($scope.data.val);
});
$scope.set_val = function(){
$scope.data.val = 2;
}
}])
.controller('childController',['$scope', function($scope){}]);
</script>
<form name="testForm" ng-controller="ExampleController">
<div ng-controller="childController">
<input ng-model="data.val" />
<input type="button" ng-click="set_val()" value="change value"/>
</div>
</form>
</body>
</html>
Here is the working Plunk.