I have a directive which shows input fields and I want to initialize those fields with data from the server. The problem is that I can't do that while using ng-model.
Before using a directive I used in the controller something like $scope.field1 = $scope.first.field1
Here's my code. I simplified it for the sake of readability but the idea's here.
In my controller I have this code:
app.controller('MyController',
['$scope', 'myData', function($scope, myData) {
myData.then(function(data) {
$scope.first = data.first;
$scope.second = data.second;
});
}]);
Inside first and second I have 2 field: field1 and field2.
In in html code, I have this bit:
<h1>First</h1>
<my-directive info="first"></my-directive>
<h1>Second</h1>
<my-directive info="second"></my-directive>
The directive is as follows:
app.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'static/js/myDirective.html',
link: function(scope, element, attrs) {
scope.doStuff = function() {
/* Do stuff with
scope.field1 and scope.field2 */
}
}
};
});
and the myDirective.html code:
<input type="text" ng-model="myfield1" />
<input type="text" ng-model="myfield2" />
<input type="submit" ng-click="doStuff()" />
If in myDirective.html I write:
<input type="text" value="info.field1" />
I can see the value fine.
Any ideas?
probably your directive initializes before your data loads. and your directive sees ng-model as an undefined variable. You are not using info directly in template so no auto $watch's for you :).
you need to $watch your info variable in directive and call your doStuff function on change.
note: i wouldn't recommend adding a controller to a directive just for this task. adding a controller to a directive is needed when you need to communicate with other directives. not for waiting async data
edit
you should do
app.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'static/js/myDirective.html',
link: function(scope, element, attrs) {
scope.doStuff = function() {
/* Do stuff with
scope.field1 and scope.field2 */
}
scope.$watch('info', function(newValue){
scope.doStuff();
});
}
};
});
Check working demo: JSFiddle.
Define a controller for the directive and do the initialization inside it:
app.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
info: '='
},
controller: ['$scope', 'myData', function ($scope, myData) {
myData.then(function(data){
$scope.first = data.first;
$scope.second = data.second;
});
}],
...
},
Inside the directive, myfield1 and myfield2 don't exist. You are close to solving the issue by using info.field1 instead.
var myApp = angular.module('myApp', []);
//Faking myData here; in your example this would come from the server
var myData = {
first: {
field1: "FirstField1",
field2: "FirstField2"
},
second: {
field1: "SecondField1",
field2: "SecondField2"
}
};
myApp.controller('MyController', ['$scope', function($scope) {
$scope.first = myData.first;
$scope.second = myData.second;
}]);
myApp.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
info: '='
},
template: '<input type="text" ng-model="info.field1" /><input type="text" ng-model="info.field2" /><input type="submit" ng-click="doStuff()" />',
link: function(scope, element, attrs) {
scope.doStuff = function() {
alert('Info: ' + scope.info.field1 + ', ' + scope.info.field2);
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<h1>First</h1>
<my-directive info="first"></my-directive>
<h1>Second</h1>
<my-directive info="second"></my-directive>
</div>
Related
I have a button and when I click on that function I need to call a directive.
For this I have writern the following code.before creating directive there is a ng-change function.I have removed ng-change and kept directive as follows,
<button upload-file="selectedDocumentName,loanFolderNumber" ><!-- ng-click="uploadFile(selectedDocumentName,FolderNumber)" -->
How can I take that arguments selectedDocumentName,FolderNumber in my directive.I have tried in the following way,but I am not getting the values.
Directive:-
app.directive('uploadFile',['documentService',function(documentService){
return {
restrict: 'AE',
scope: {
selectedDocumentName: '=',
FolderNumber: '=',
},controller: function($scope){
$scope.selectedDocumentName;
},
link : function($scope,element,attrs){
element.on('click',function(e){
})
}
}
}]);
Try this
<button upload-file obj="obj">A</button>
var myApp = angular.module('myApp',[]);
myApp.directive('uploadFile', function() {
return {
restrict: 'AE',
scope: {
obj1: '='
},controller: function($scope){
$scope.obj2 = JSON.parse(JSON.stringify($scope.obj1))
console.log($scope.obj2.selectedDocumentName);
$scope.obj2.selectedDocumentName = "DEF";
console.log($scope.obj2.selectedDocumentName);
},
link : function($scope,element,attrs){
element.on('click',function(e){
})
}
}
});
myApp.controller('MyCtrl', function ($scope) {
$scope.obj = {selectedDocumentName : "ABC",loanFolderNumber : "DEDF"};
});
Check this fiddle
Hi Im trying to create a directive to pass some value to my ng-model,
in my directive i have a controller inside my directive and and i want to pass the value of it in my ng-model
Lets just say i have a string value, when i click the $scope.speakUP it should be pass it on the ng-model
.directive('speak', function(){
return {
restrict: 'A',
require: 'ngModel',
scope: true,
template: '<i ng-click = "speakUP()" class="icon ion-mic-a larger"></i>',
controller: function($scope, $element){
$scope.speakUP = function(){
$scope.passThisString = "Sample Data";
}
}
This is my HTML
<input type="text" ng-model="sampleModel" speak>
this is a quick example from where you can start implement your goals.
app.directive('inputField', function () {
return {
require: '?ngModel',
template: '<input ng-model="value" ng-change="onChange()"><i ng-click="speakUP()" class="icon ion-mic-a larger">click</i>',
link: function ($scope, $element, $attrs, ngModel) {
if (!ngModel) return;
$scope.speakUP = function(){
ngModel.$setViewValue('your data');
ngModel.$render();
}
$scope.onChange = function() {
ngModel.$setViewValue($scope.value);
};
ngModel.$render = function() {
$scope.value = ngModel.$modelValue;
};
}
};
});
HTML
<input-field name="sampleModel" ng-model="sampleModel"></input-field>
I have a template for my directive, which contains a scope variable called content:
<div class="directive-view">
<span class="directive-header">My Directive</span>
<span ng-bind-html="content"></span>
</div>
I have the following directive, which watches for changes to content and then compiles the element's contents:
(function () {
"use strict";
angular
.module('myApp.myDirective', [])
.directive("myDirective", myDirective);
function myDirective($compile, $sce) {
return {
restrict: 'E',
scope: {
},
templateUrl:'../partials/directives/my-directive.html',
controller: function($scope) {
$scope.testAlert = function(msg) { alert(msg) };
},
link: function (scope, element, attrs, ctrl) {
scope.content = $sce.trustAsHtml('Initial value');
scope.$watch(attrs.content, function(value) {
element.html(value);
console.log("Content changed -- recompiling");
$compile(element.contents())(scope);
});
scope.content = $sce.trustAsHtml('<button ng-click="testAlert(\'clicked!\')">Click</button>');
}
};
}
})();
The directive renders the button element. However, the controller function testAlert() does not get called when the button element is clicked on.
Also, the $watch callback is called only once, after content is set to Initial value. The callback is not triggered after content is set to the button. (I would have thought that the callback is triggered when the value of attrs.content is changed.)
If I manually recompile the element:
$compile(element.contents())(scope);
the button element still does not trigger the testAlert function when clicked.
How do I correctly recompile the element contents, so that the correct bindings are made?
You do not need use $sce in this case. Use just $compile.
Live example on jsfiddle.
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.name = 'Superhero';
$scope.changeTEmplate = function(){
$scope.cont = '<div><b>i\'m changed</b></div>';
}
})
.directive("myDirective", function myDirective($compile) {
return {
restrict: 'E',
scope: {content:"="},
template: `<div class="directive-view">
<span class="directive-header">My Directive</span>
<span></span>
</div>`,
controller: function($scope) {
$scope.testAlert = function(msg) {
alert(msg)
};
},
link: function(scope, element, attrs, ctrl) {
scope.$watch('content', function(value) {
var span = angular.element(element.find('span')[1]);
span.html(value);
console.log("Content changed -- recompiling",value);
$compile(span)(scope);
});
scope.content = '<button ng-click="testAlert(\'clicked!\')">Click</button>';
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
Hello, {{name}}!
<button ng-click="changeTEmplate()"> change Content</button>
<my-directive content="cont"></my-directive>
</div>
</div>
I'm working on a page that is made up of 5 directives, for example:
<directive-one></directive-one>
<directive-two></directive-two>
<directive-three></directive-three>
<directive-four></directive-four>
<directive-five></directive-five>
I would like to be able to re-order these on demand so that a user can control how their page looks. The only way I could think of doing that was putting them in an ng-repeat:
$scope.directiveOrder = [{
name: "directive-one",
html: $sce.trustAsHtml('<directive-one></directive-one>'),
order: 1
}, ...
HTML:
<div ng-repeat="directive in directiveOrder" ng-bind-html="directive.html">
{{directive.html}}
</div>
This will give me the right tags, but they aren't processed as directives by angular. Is there a way around that? I'm assuming it's something to do with $sce not handling it, but I might be way off?
Try creating a new directive and using $compile to render each directive:
https://jsfiddle.net/HB7LU/18670/
http://odetocode.com/blogs/scott/archive/2014/05/07/using-compile-in-angular.aspx
HTML
<div ng-controller="MyCtrl">
<button ng-click="reOrder()">Re-Order</button>
<div ng-repeat="d in directives">
<render template="d.name"></render>
</div>
</div>
JS
var myApp = angular.module('myApp',[])
.directive('directiveOne', function() {
return {
restrict: 'E',
scope: {},
template: '<h1>{{obj.title}}</h1>',
controller: function ($scope) {
$scope.obj = {title: 'Directive One'};
}
}
})
.directive('directiveTwo', function() {
return {
restrict: 'E',
scope: {},
template: '<h1>{{obj.title}}</h1>',
controller: function ($scope) {
$scope.obj = {title: 'Directive Two'};
}
}
})
.directive("render", function($compile){
return {
restrict: 'E',
scope: {
template: '='
},
link: function(scope, element){
var template = '<' + scope.template + '></' + scope.template + '>';
element.append($compile(template)(scope));
}
}
})
.controller('MyCtrl', function($scope, $compile) {
$scope.directives = [{
name: 'directive-one'
}, {
name: 'directive-two'
}];
$scope.reOrder = function () {
$scope.directives.push($scope.directives.shift());
console.log($scope.directives);
};
});
I hope You can easily done it.
var myApp = angular.module('myApp',[])
.directive('directiveOne', function() {
return {
restrict: 'E',
scope: {},
template: '<h1>{{obj.title}}</h1>',
controller: function ($scope) {
$scope.obj = {title: 'Directive One'};
}
}
})
.directive('directiveTwo', function() {
return {
restrict: 'E',
scope: {},
template: '<h1>{{obj.title}}</h1>',
controller: function ($scope) {
$scope.obj = {title: 'Directive Two'};
}
}
});
myApp.controller('ctrl',function($scope){
$scope.data = [{name:'directive-one'},{name:'directive-two'}];
});
<html ng-app='myApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js"></script>
</head>
<body ng-controller='ctrl'>
<div ng-repeat='item in data'>
<item.name></item.name>
<directive-one></directive-one>
</body>
</html>
I have created custom angular directive. For an example:
Custom directive:
var app=angular.module('app',[]);
app.directive('customDirective',function(){
return{
restrict:A,
controller:customDirectiveController,
scope:{
someArray:"="
}
}
})
Custom directive controller:
app.controller('customDirectiveController',function(scope){
scope.someArray=[];
scope.someArray.push(1);
scope.someArray.push(2);
scope.someArray.push(3);
});
Parent controller:
app.controller('parentCtrl',function($scope){
$scope.result=[];
});
HTML:
<div data-ng-controller="parentCtrl">
<div data-custom-directive="result">
</div>
How can I get value of this someArray from custom directive into Parent controller( result variable should in Parent controller be same as someArray from custom directive controller)?
Here is jsfiddle http://jsfiddle.net/mehmedju/RmDuw/302/
Thanks
You can apply a '$watch' on the array like this:
In the controller:
app.controller('MainCtrl', function($scope) {
$scope.someArray = [];
})
In the HTML:
<div custom-directive arr="someArray">
</div>
In the directive:
app.directive('customDirective', function(){
return {
scope: {
arr: '='
}
}
link: function(scope, element, attrs) {
scope.$watch('arr', function(newVal, oldVal) {
//do your array manipulation here
}
}
})
Alternatively, if you just want to send data back, here's the method:
In the controller, create a function which will accept the value returned from the directive, example:
app.controller('MainCtrl', function(){
$scope.watchVal = function(val) {
//do array manipulation
$scope.apply(); //to update the scope
}
})
In the HTML:
<div custom-directive data-method="watchVal">
</div>
In the directive:
app.directive('customDirective', function(){
return {
scope: {
sendVal: '&method'
},
link: function(scope, element, attrs){
scope.updateVal = function(){
var func = scope.sendVal();
func(scope.someArray);
}
}
}
})
Let's just say you are using tempController
So your code should be
app.controller('tempController', function($scope) {
scope.someArray = []
});
Html Code for this is
<div ng-controller="tempController">
<div custom-directive some-array="someArray">
</div>
You have here a very interesting article about watchers
http://teropa.info/blog/2014/01/26/the-three-watch-depths-of-angularjs.html
You need use a watchCollection
And, If you are playing creating the array and change the reference inside the directive you can lost the reference inside the watcher. This mean don't create o change the array reference inside.
Another interesting way is use ngModel
http://jsfiddle.net/ta66J/
var app = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.formVals = {
dirVals: [
{val: 'one'},
{val: 'two'}
]
};
}
app.directive('dir', function($compile) {
return {
restrict: 'E',
compile: function(element, attrs) {
var html = "<input id='inputId' type='text' ng-model='" + attrs.dirModel + "' />";
element.replaceWith(html);
return function(scope, element, attrs, ngModel) {
$compile(angular.element(element))(scope);
};
},
};
});
The jsfidler is from this interesting thread:
https://groups.google.com/forum/#!topic/angular/QgcRBpjiHAQ
Here is the fixed issue.
<div custom-directive="" data-some-array="result"></div> {{result}}
[http://jsfiddle.net/mehmedju/RmDuw/304/][1]