AngularJS ng-model in custom directives - javascript

I'm creating a directive with ng-model. So I can pass the model to these directives.
Here is what I think about it:
app.js
app.directive('testDir', function(){
return {
templateUrl: 'assets/views/dir.html',
restrict: 'E',
required: 'ngModel'
};
});
dir.html
<div>
<h1>Test directive</h1>
<h3>{{name}}</h3>
</div>
index.html
<div class="container" ng-controller="testCtrl">
<test-dir ng-model="user"></test-dir>
</div>
and the contoller
$scope.user = {
name: 'John Doe'
};
I can see the <h1> tag with Test directive text but nothing in the <h3>
tag
I know it is a very beginner problem, but right know I can't find any solution.
Thank you!

The syntax for scope was missing. Please see a working example below
var app = angular.module("sa", []);
app.controller("testCtrl", function($scope) {
$scope.user = {
name: 'John Doe'
};
});
app.directive('testDir', function() {
return {
//templateUrl: 'assets/views/dir.html',
template: '<div>' +
'<h1>Test directive</h1>' +
'<h3>{{fooModel.name}}</h3>' +
'</div>',
restrict: 'E',
required: 'ngModel',
scope: {
fooModel: '=ngModel'
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sa" class="container" ng-controller="testCtrl">
<test-dir ng-model="user"></test-dir>
</div>

Try This, you need to create a scope variable for ng-model
app.directive('testDir', function(){
return {
templateUrl: 'assets/views/dir.html',
restrict: 'E',
required: 'ngModel',
scope: {
ngModel:'='
}
};
});
HTML
<div>
<h1>Test directive</h1>
<h3>{{ngModel}}</h3>
</div>

Related

Where to define a local function in a AngularJS Directive

Where do I have to define my function button() in the directive, such that pressing the button will trigger the function?
I don't want to use the outer scope of the app, I just want to use the local scope.
var app = angular.module("myApp", []);
app.directive('aaaa', function() {
return {
restrict: 'E',
scope: {
data: '=',
//this is not working: button: function(){console.log('hello from button');}
},
link: function(scope, element) {
element.append('hello');
element.append(' <button type="button" ng-click="button()">Click Me!</button> ')
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<aaaa></aaaa>
</div>
As #tymeJV said , you need to compile the html first and then call button() in directive controller
var app = angular.module("myApp", []);
app.directive('aaaa', function($compile) {
return {
restrict: 'E',
scope: {
data: '=',
//this is not working: button: function(){console.log('hello from button');}
},
link: function(scope, element) {
element.append('hello');
var htmlText = ' <button type="button" ng-click="button()">Click Me!</button> ';
var template = angular.element($compile(htmlText)(scope));
element.append(template);
},
controller: function($scope, $element){
$scope.button = function(){
console.log('button clicked');
}
}
}
});
I would advise to use angular templates instead of element.append, see example code below. Then you don't need all the compiler code 'n stuff.
You could also replace "template: 'hello
var app = angular.module("myApp", []);
app.directive('aaaa', function() {
return {
restrict: 'E',
scope: {
data: '='
},
link: function(scope, element) {
scope.button = function(){
console.log('hello from button');
};
},
template: 'hello <button type="button" ng-click="button()">Click Me!</button>'
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<aaaa></aaaa>
</div>
you can out under link
link: function(scope, element) {
element.append('hello');
element.append(' <button type="button" ng-click="button()">Click Me!</button> ');
scope.button=function(){
//content goes here
}
}

Angular isolated scope values not visible in template when using replace

I am creating a small app and I have the following directive with the template.
smallgrid.directive.js:
angular.module('myActions')
.directive('smallgrid', ['$rootScope', function($rootScope) {
return {
restrict: "E",
scope: {
actionable: "="
},
controller: function($scope) {
$scope.setLocation = function() {
console.log("yee");
};
}
};
}])
.directive('three', function() {
return {
replace: true,
templateUrl: '/app/my_actions/directives/templates/grid3x3.template.html'
};
})
.directive('four', function() {
return {
replace: true,
templateUrl: '/app/my_actions/directives/templates/grid4x4.template.html'
};
})
.directive('five', function() {
return {
replace: true,
templateUrl: '/app/my_actions/directives/templates/grid5x5.template.html'
};
});
grid3x3.template.html
<div class="k-edit-field" id="board">
<div class="row" ng-click="setLocation()">
{{actionable.probability}}
</div>
</div>
I use this directive as follows:
<smallgrid three actionable="currentAction.actionable" ng-if="somecondition"></smallgrid>
The UI renders properly. However it shows {{actionable.probability}} is empty and the Click event is not firing. However, if I remove the isolated scope and access the variable directly, values are available. I understand that when I am using isolated scopes, in the three directive, I can't access values of smallgrid. Is there a way to pass those values from smallgrid to the template?
Passing a directive as an attribute of a directive you're bound to have scope problems.
It will look better if you use scope inheritance for nested directives with ng-transclude.
So your starting point should be
<smallgrid actionable="currentAction.actionable" ng-if="somecondition">
<three></three>
</smallgrid>
This way <three> has access to the $parent
function smallgrid() {
return {
restrict: "E",
transclude: true,
scope: {
actionable: "="
},
template: `<div ng-transclude></div>`,
controller: function($scope) {
$scope.setLocation = function() {
console.log("yee");
};
}
};
}
function three() {
return {
template: `<div class="k-edit-field" id="board">
<div class="row" ng-click="$parent.setLocation()">
test = {{$parent.actionable.probability}}
</div>
</div>`
};
}
function myController($scope) {
$scope.currentAction = {actionable: {probability: "test"}};
$scope.somecondition = true;
}
angular.module('myApp', []);
angular
.module('myApp')
.controller('myController', myController)
.directive('smallgrid', smallgrid)
.directive('three', three);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<smallgrid actionable="currentAction.actionable" ng-if="somecondition">
<three></three>
</smallgrid>
</div>
</div>

Angular setting new variables in custom directives

I am following a course on Angular and as a complete newbie I have a newbie question to ask about custom directives. I wonder how can we set new variables in that custom directive and access them in our view, is that even possible, if somebody could explain that in a clear way?
For example:
myApp.controller('mainController', ['$scope', '$log', function($scope, $log) {
$scope.person = {
name: 'John Doe',
address: '555 Main St., New York, NY 11111'
}
}]);
myApp.directive("searchResult", function() {
return {
restrict: 'AECM',
templateUrl: 'directives/searchresult.html',
replace: true,
scope: {
personName: "#",
personAddress: "#",
newVariable: "someValue"
}
}
});
searchresult.html
<a href="#" class="list-group-item">
<h4 class="list-group-item-heading">{{ personName }}</h4>
<p class="list-group-item-text">
{{ personAddress }}
</p>
<p class="list-group-item-text">
{{ newVariable }}
</p>
main.html
<label>Search</label>
<input type="text" value="Doe" />
<h3>Search Results</h3>
<div class="list-group">
<search-result person-name="{{ person.name }}" person-address="{{ person.address }}" newVariable="{}"></search-result>
use link function for local scope
myApp.directive("searchResult", function() {
return {
restrict: 'AECM',
templateUrl: 'directives/searchresult.html',
replace: true,
scope: {
personName: "#",
personAddress: "#"
},
link: function(scope, elem, attr) { scope.newVariable='something'; },
};
});
Use This.
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){ $scope.name = "Abc"; $scope.reverseName = function(){
$scope.name = $scope.name.split('').reverse().join(''); }; });
app.directive("myDirective", function(){ return {
restrict: "EA",
scope: false,
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='`enter code here`text' ng-model='name' />" }; });

AngularJS: Requiring a parent directive from child directive

Please consider this Plunk.
I'm trying to set up a test case for complex directive access, but I get an error calling a method from the parent directive:
Parent directive
app.directive('topParentDirective', [
'$compile',
function($compile){
return {
restrict: 'E',
transclude: true,
template: '<h3>I\'m the parent directive.</h3><div ng-transclude></div>',
controller: function($scope) {
$scope.ActivateMe = function(callerName) {
alert('Parent activated from caller ' + callerName);
};
}
};
}
]);
Child directive
app.directive('interactingChildDirective', [
'$compile',
function($compile){
return {
scope: {
name: '#'
},
restrict: 'E',
require: ['^topParentDirective'],
templateUrl: 'interactingChildDirective.html',
link: function($scope, $elem, $attrs, $ctrl) {
var self = {};
console.log($ctrl);
$scope.CallTopParent = function() {
$ctrl.ActivateMe($attrs.name);
};
}
};
}
]);
InteractingChildDirective.html
Contains:
My name is {{name}}, <button ng-click="CallTopParent()">Click me</button>!
Html
<body ng-app="ngApp">
<div ng-controller="myController">
<top-parent-directive>
<interacting-child-directive name="Child 1"></interacting-child-directive>
</top-parent-directive>
</div>
</body>
Issue
TypeError: $ctrl.ActivateMe is not a function
at n.$scope.CallTopParent
Which is the case because $ctrl doesn't seem to be correct.
How can I fix this? It's likely something ridiculously easy ...
It should be
controller: function($scope) {
this.ActivateMe = function(callerName) {
alert('Parent activated from caller ' + callerName);
};
}
Because $ctrl gets required controller's this.
Because you have nested the child in the parents controller you can access it's scope by using
$scope.$parent
in your case:
$scope.$parent.ActivateMe($attrs.name);
Plunker: http://plnkr.co/edit/YyppT9pWnn1PFWJXBAOF?p=info
The answer by estus, combined by the comments, works. To be complete, a working sample of the scenario I was aiming for:
Plunkr sample.
Updated Html
<body ng-app="ngApp">
<div ng-controller="myController">
<top-parent-directive>
<interacting-child-directive name="Child 1">
<meaningless-level-directive header="Sub 1">
<interacting-child-directive name="Child 3"/>
</meaningless-level-directive>
</interacting-child-directive>
<interacting-child-directive name="Child 2">
<meaningless-level-directive header="Sub 2">
<interacting-child-directive name="Child 4"/>
</meaningless-level-directive>
</interacting-child-directive>
</top-parent-directive>
</div>
</body>
meaninglessLevelDirective
As the name suggests this is just to add an extra level:
app.directive('meaninglessLevelDirective', [
'$compile',
function($compile){
return {
scope: {
header: '#'
},
restrict: 'E',
transclude: true,
templateUrl: 'meaninglessLevelDirective.html',
controller: function($scope){
}
};
}
]);
meaninglessLevelDirective.html
<div class="meaninglessLevelStyle">
{{header}}
<div style="padding: 10px" ng-transclude>
</div>
</div>

Angularjs 1.2.9 Scope Isolation

I'm using Scope Isolation in one of my directives. However, this doesn't seem to work:
<div ng-controller="MyCtrl">
Hello, {{name}}!
<dir info='spec'>
{{ data }}
</dir>
</div>
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
$scope.spec = 'Super';
}
myApp.directive('dir', function(){
return {
restrict: 'AE',
scope:{
data: '=info'
}
}
});
Fiddle: enter link description here
Here is a fiddle: http://jsfiddle.net/WA5t5/
Since this commit(1.2) Child elements that are defined either in the application template or in some other
directives template do not get the isolate scope.
You can do this instead:
myApp.directive('dir', function(){
return {
restrict: 'AE',
scope:{
data: '=info'
},
template: "{{ data }}"
}
});
If you want to alter this behavior check my other answer: Why I can't access the right scope?
Try:
myApp.directive('dir', function(){
return {
restrict: 'AE',
scope:{
data: '=info'
},
template:"<div>{{data}}</div>"
}
});
DEMO
Another solution using transclusion to bind the scope yourself:
myApp.directive('dir', function(){
return {
restrict: 'AE',
scope:{
data: '=info'
},
transclude:true,
compile: function (element, attr, linker) {
return function (scope, element, attr) {
linker(scope, function(clone){
element.append(clone); // add to DOM
});
};
}
}
});
You can still use the same html as before:
<div ng-controller="MyCtrl">
Hello, {{name}}!
<dir info='spec'>
{{data}}
</dir>
</div>
DEMO
You should have a template defined in your directive where you show the data scope variable. The html code does not know what the data scope variable is, it's only known in the directive's template. See this demo
myApp.directive('dir', function () {
return {
restrict: 'AE',
scope: {
data: '=info'
},
link: function (scope, element, attrs) {
console.log(scope.data);
},
template: 'Hello {{data}}'
}
});

Categories