How to specify model in AngularJS custom directives? - javascript

I want to generate the following code using an AngularJS custom directive:
<body ng-app="">
<label>Number 1: <input type="number" ng-model="a2"/></label> +<br/>
<label>Number 2: <input type="number" ng-model="b2"/></label> =<br/>
<hr/>
<span>Total: {{a2+b2}}</span>
</body>
Therefore, I wrote the following code:
<script>
var app = angular.module('my-total', []);
app.directive('myNumber', function() {
return {
restrict: 'E',
scope: {
myLabel: '=',
ngModel: '=',
},
template: '<label>{{myLabel}}: <input type="number" value="{{ngModel}}"/></label>',
}
});
</script>
<body ng-app="my-total">
<my-number my-label="'Number 1'" ng-model="a1"/></my-number> +<br/>
<my-number my-label="'Number 2'" ng-model="b1"/></my-number> =<br/>
<hr/>
<span>Total: {{a1+b1}}</span>
</body>
When the user types the numbers, the total is not shown.
How can I make it work? I mean, how can I pass the model variables "a1" and "b1" out of the directive?

You should make change to your input field inside your template, it should use ng-model="ngModel" instead of value="{{ngModel}}"
app.directive('myNumber', function() {
return {
restrict: 'E',
scope: {
myLabel: '=',
ngModel: '=',
},
template: '<label>{{myLabel}}: '+
'<input type="number" ng-model="ngModel"/>'+ //<-- change here
'</label>',
}
});

Hey Please find working fiddle for the same.
angular.module('test', [])
.directive('myDir', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
template: '<label>Enter value: '+
'<input type="number" ng-model="ngModel"/>'+
'</label>',
};
});

Related

How to access isolated scope property from static directive template in Angular?

Controller:
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.temp = {
'name': 'Test'
};
}]);
Template:
<custom-field ng-model="temp.name">
<md-input-container class="addon-menu">
<label>Name</label>
<input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" />
</md-input-container>
</custom-field>
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
}
};
});
The problem is that once template is rendered, I can't see the value attached to input - it's empty, but I'm expecting to works, because inside link function it's printed correctly.
You are trying to access the directive scope in your template as the controller's scope. Move the markup inside the directive's template instead.
Directive:
app.directive('customField', function($timeout) {
return {
restrict: 'E',
scope: {
ngModel: '='
},
link: function($scope, $element, $attrs) {
console.log($scope.ngModel); // prints "test"
},
template: '<md-input-container class="addon-menu"><label>Name</label><input ng-model="ngModel" type="text" ng-focus="setLastFocusedElement($event)" /></md-input-container>'
};
Template:
<custom-field ng-model="temp.name"></custom-field>
You can also use separate html files as directive templates, which is good practise.
Are you trying to see the value in controller?
Please try $parent.$scope to see if value exist.

Angularjs ng-click clear input and update scope

1. Directive:
app.directive('inputField', function() {
return {
restrict: 'E',
require: 'ngModel',
scope: {
words: '=ngModel'
},
transclude: true,
template: "<input type='text' ng-model='words' placeholder='Translate' />"
};
});
2. ng-click function:
$scope.clear = function() {
$scope.words = { word: '' };
};
3. View looks like this:
<input-field id='inputWord' value='' name="data1" ng-model="words.word"></input-field>
After click clear() {{words.word}} and value in input still exist and $scope is broken.
Please tell me how I can clear all inputs ng-repeat and update scope?
Try like this.
var app = angular.module('app',[])
app.controller('ctrl',function($scope){
$scope.words = [ {word : 'input1'}, {word : 'input2'}, {word : 'input3'}];
$scope.clear = function() {
$scope.words =[ {word : ''}, {word : ''}, {word : ''}];
};
});
app.directive('inputField', function() {
return {
restrict: 'E',
require: 'ngModel',
scope: {
words: '=ngModel'
},
transclude: true,
template: "<input type='text' ng-model='words' placeholder='Translate' />"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div ng-repeat="word in words">
<input-field id='inputWord' name="data1" ng-model="word.word"></input-field>
</div>
<button ng-click="clear()">Clear</button>
</div>

AngularJS ng-model in custom directives

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>

Directive inside a Directive with transclude?

Hey Stackoverflow peep.
This works:
angular.module('demoApp', [])
.controller('MainController', function($scope) {
$scope.Data = {
name: "Bob"
}
}).directive("formText", function() {
return {
template: '<div><input type="text" ng-model="data" name="{{key}}" id="{{key}}"></div>',
restrict: 'EA',
scope: {
label: "#label",
key: "#key",
data: "="
}
};
});
https://jsfiddle.net/ownmph09/4/
That fiddle works. You can change controller scope value. Pretty straight forward.
But this one does not:
angular.module('demoApp', [])
.controller('MainController', function($scope) {
$scope.Data = {
name: "Bob"
}
}).directive("formText", function() {
return {
template: '<div form-input label="{{label}}"><input type="text" ng-model="data" name="{{key}}" id="{{key}}"></div>',
restrict: 'EA',
scope: {
label: "#label",
key: "#key",
data: "="
}
};
}).directive('formInput', function() {
return {
template: '<div class="form-group"><label class="col-sm-4 control-label">{{label}}</label><div class="col-sm-8" ng-transclude></div></div>',
restrict: 'EA',
transclude: true,
scope: {
label: "#label"
}
};
});
https://jsfiddle.net/ownmph09/3/
I'm sure it has to do with the transclude and isolated scopes but I don't quite understand what's going on. Hoping someone that knows this stuff better than me can help.

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>

Categories