Directive Angularjs, $watch and HTML Element - html

I have a question. I coded a HTML page with an angularjs directive
this is my code
<menufileupload visible="rightVisible" alignment="right">
<input type="text" ng-model='expr'/>
<!--Other stuff-->
</menufileupload>
I'm trying to use a $watch to check any change in the text field
$scope.$watch(...) only worked when the text field is out of the
directive. So I think that I have to create a $watch in the directive. I did that. But it didn't work.
Directive
app.directive("menufileupload", function() {
return {
restrict: "E",
template: "<div>bla</div>",
link: function(scope, elem, attrs) {
scope.$watch('expr', function(obj) {
alert("it changed");
}, true);
}
};
});
Thanks for your help

You have a template in your directive, so everything inside it will be replaced by that <div> tag.
It works fine if you remove the template. I made a codepen example of your code:
http://codepen.io/argelius/pen/jEzQVJ
angular.module('test', [])
.directive('menufileupload', function () {
return {
restrict: "E",
link: function(scope, elem, attrs) {
scope.$watch('expr', function(obj) {
alert("it changed");
}, true);
}
};
});
If you want your input element to be shown inside the directive DOM you should use the ngTransclude directive. Please check it out in the documentation.

Related

ANGULAR: link function not being called on click in custom directive

I'm in the middle of refactoring an old project to use custom directives, and I'm already running into a problem. I'm just trying to make a simple directive and build from there. I have a logger function in my directive's link function that just runs a console.log. I'm not sure what I'm missing here, and I'm sure it's something simple. Here's my directive:
'use strict';
(function() {
angular
.module('sigFig')
.directive('myDirective', myDirective);
function myDirective(sigFigFactory) {
var directive = {
restrict: 'E',
replace: 'true',
templateUrl: 'Directives/directiveTemplate.html',
link: link,
compile: compile
};
return directive;
function link(scope, element, attrs) {
scope.logger = function() {
console.log('DING!!!');
}
}
function compile(scope, element, attrs) {
console.log('I AM A COMPILE FUNCTION');
}
}
})();
The HTML template for it is just:
<button ng-click="logger()">CLICK ME</button>
And I'm calling it in my HTML like this:
<my-directive></my-directive>
The button appears and that console.log in my compile works, but the ng-click does not. What is it I'm missing? Thanks in advance!
Add scope to directive variable: scope:{},
function myDirective(sigFigFactory) {
var directive = {
scope:{},
restrict: 'E',
replace: 'true',
templateUrl: 'Directives/directiveTemplate.html',
link: link,
compile: compile
};
return directive;
I have never created an angular application without a controller. So I'm positive that that is your issue here.
Example of your code with a controller.
html:
<body ng-app='sigFig' ng-controller='ctrl'>
<my-directive></my-directive>
</body>
js:
(function() {
angular.module('sigFig', [])
.controller('ctrl', function($scope){
$scope.itemH = 'hahaha'
})
.directive('myDirective', myDirective);
function myDirective() {
return {
restrict: 'E',
template: '<button ng-click="logger()">{{item}}</button>',
link: function link(scope, element, attrs) {
scope.item = "Logger Click Me";
scope.logger = function() {
alert('logger')
}
}
};
function compile(scope, element, attrs) {
console.log('I AM A COMPILE FUNCTION');
}
}
})();

angular directives not working with my directive

i created a directive called bootstrap-switch and put it as attribute to and input tag.
now, when i am trying to add some angular directives (like: ng-show, ng-disabled) it isn't working!
the html:
<input ng-show="false" type="checkbox" name="my-checkbox" bootstrap-switch>
the js:
sharedSwitch.directive('bootstrapSwitch', ["regService",
function(regService) {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (Number(attrs.ioStatus))
{
$(element).bootstrapSwitch('state',true,true);
}
else
{
$(element).bootstrapSwitch('state',false,true);
}
$(element).bootstrapSwitch('onSwitchChange',function(event,state){
flagNumber = Number(scope.baseFlag) + Number(scope.$index);
regService.fSave('F',flagNumber ,state);
});
}
};
}
]);
the input is showed any way.. and that because of the "bootstrap-switch" and i dont know why or how to fix it...
thank you for your help!

Unable to access $scope model

In my main html, I have a view which loads templates.
<div data-ng-view></div>
It loads a html whenever the link is clicked.
app.config(["$routeProvider", function ($routeProvider) {
'use strict';
$routeProvider
.when("/", {
templateUrl: "events.html"
});
}]);
On this page (template) , I have a directive which loads another html file
app.directive('ngPost', function () {
'use strict';
return {
restrict: 'A',
templateUrl: 'postbox.html'
};
});
I then use this directive on my events.html page by using <div data-ng-Post></div>
In postbox, I have two input fields and a button
<input type="text" id="user" data-ng-model="username" />
<input type="text" id="mess" data-ng-model="message"/>
<button data-ng-click="Add(eventid-1, username, message)">Post</button>
Upon clicking the button, I have some operations, then I try to clear the input fields, but I cannot. Method here :
$scope.Add = function (index, uname, msg) {
var a = {user: uname, message: msg, time: new Date()};
$scope.data[index].messages.push(a);
$scope.message = ''; // clearing here
$scope.username ='';
};
The clearing does not happen, I do not know why. My controller that has this Add method wraps the <div data-ng-view></div>in the main html file so it is the outermost controller and should have access to all $scope models inside. Why does it not work?
Note that the operations before the clearing works with no problems
Your add method is in the parent scope. The parent's scope cannot see it's children, it works the other way around. The message and username properties are defined in the directive's child scope. From a child you can reference parent properties, but not the other way around.
If you add scope: false and transclude: false to your directive, it won't create it's own scope and instead use its parent's scope, so your directive would look something like this:
angular.module('app', []).controller("myController",myController);
function myController($scope){
var ctrl = this;
ctrl.hello ="Hello"
};
angular.module('app').directive("childThing", function() {
return {
template: '<div>{{message}}</div><div>{{username}}</div>',
scope: false,
transclude: false,
controller: function($scope) {
$scope.username="Mike Feltman"
$scope.message="Hi Mike"
}
}
})
and you can access the elements that the directive adds to the scope from the parent like this:
<div ng-controller="myController as ctrl">
{{username}} in the parent.
<div>{{ctrl.hello}}</div>
<child-thing></child-thing>
</div>
Update using your template:
{{username}} in the parent.
{{ctrl.hello}}
Javascript:
function myController($scope){
var ctrl = this;
ctrl.hello ="Hello"
$scope.add = function() {
alert($scope.username)
}
};
angular.module('app').directive("childThing", function() {
return {
template: '<input type="text" id="user" data-ng-model="username" /><input type="text" id="mess" data-ng-model="message"/>',
scope: false,
transclude: false,
}
})

getting a attribute value in a directive in angular js

I have a directive
configModule.directive('iMemoryDiv',function () {
return {
restrict: 'E',
scope: {},
replace: true,
templateUrl: '/memoryDiv.html',
link: function(scope, el, attrs) {
scope.iObj = scope.$parent[attrs.bIObject];
if(angular.isDefined(scope.iObj)){
getSummary(scope.iObj);
}
function getSummary(iObj){
}
}
};
}
);
and I am calling it from html by passing an object attribute
<i-memory-div b-i-object="app"></i-memory-div> //here app is declared in a respective controller
but, here directive is getting loaded before the controller where value for 'app' is getting assigned.So scope.iObj = scope.$parent[attrs.bIObject] is always giving me undefined.
How can make directive load after the app value is getting assigned ??
Isn't it easier doing it this way:
configModule.directive('iMemoryDiv',function () {
return {
restrict: 'E',
scope: {
'bIObject': '=',
'getParentObject': '&'
},
replace: true,
templateUrl: '/memoryDiv.html',
link: function(scope, el, attrs) {
scope.$watch('bIObject', function(newValue) {
if(angular.isDefined(newValue)) {
getSummary(scope.getParentObject({name: newValue}));
}
});
function getSummary(iObj){
}
}
};
}
Or do you need more from the parent scope??
You could give your directive an isolated scope and add bIObject as a scope property:
scope: {
bIObject: '=',
},
you could then put your code in the controller: rather than link:
Use $observe service in link function,like this
if(attrs. bIObject) {
attrs.$observe('bIObject', function(value) {
console.log(value);
})
}

Bind a new ngModel on an existing element

Suppose I have something that looks like this:
<input ng-model="object.properties.property_name" options="{ updateOn: 'blur' }" ng-change="object.save('property_name')">
I would like that to instead be really short like this:
<input name="property_name" autosave="object">
But to do that I need to dynamically bind an ngModel to the existing input. I've shortened it up so far to look like this:
<input ng-model="object.properties.property_name" name="property_name" autosave="object">
And this is the directive that gets me that far:
.directive('autosave', [function() {
return {
restrict: 'A',
scope : {
autosave : '=',
},
link: function(scope, element, attrs) {
element.bind('change', function(){
scope.autosave.save(attrs.name);
});
}
}
}])
How do I dynamically add scope.autosave.properties[attrs.name] to the ngModel and bind it to the input tag?
I haven't found a way to create a model, which was the original question, but I have made it shorter by pulling the property name from the model like this:
<input ng-model="object.properties.property_name" autosave="object">
and this directive
.directive('autosave', [function() {
return {
restrict: 'A',
scope : {
autosave : '=',
},
link: function(scope, element, attrs) {
element.bind('change', function(){
var property_name = attrs.ngModel.match(/(?=[^.]*$)(\w+)/)[1];
scope.autosave.save(property_name);
});
}
}
}])
It's not ideal, but it's better.