I am trying to build an AngularJS directive which will detect an input checkbox value change, but for some reason the on change event is never triggered. Can someone please check my code and tell me what I am missing / doing wrong here? Thanks
myApp.directive('supportAmntCb', function () {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function(){
console.log('Value. '+ element[0].value); //this line is never reached...
});
}
};
});
HTML
When checked...
<input id="s1" name="s1" type="checkbox" value="50" support-amnt-cb />
Unchecked...
<input id="s1" name="s1" type="checkbox" value="0" support-amnt-cb />
Note: After several tests I noticed that with styling (CSS) applied to the checkboxes the directive can't detect value change....with styling (CSS) removed, the directive can easily detect change in value....can't figure out the relation between 'styling / css' and directive inability to detect change in value....any thoughts?
Related
I have a button with this attribute: ng-disabled="ProductionBtnDisabled".
When angular renders the html the value of ProductionBtnDisabled is undefined and after initiating the controller ProductionBtnDisabled has the correct value.
So, at first the ng-disabled is not disabled because undefined=false in javascript/angular. This is a problem for me. I want the default value to be true.
Is any one has any suggestion to handle this?
What about using ng-cloak? It didn't work for me. I don't mind hiding the buttons until the scope is rendered.
Thanks!
I think there is no default settings for ngDisabled. If you needs a global solution, you can try directive.
.directive('specialDisabled',function() {
return {
restrict: 'A',
scope:{specialDisabled: '='},
link: function(scope, element, attrs) {
scope.$watch(function(){return scope.specialDisabled}, function(){
// set disabled attribute here
element[0].disabled = !scope.specialDisabled;
});
}
}
});
Then, you can called specialDisabled directive anywhere.
<input type="checkbox" ng-model="chk">
<button special-disabled="chk">My Button</button>
http://plnkr.co/edit/BA2ntTrzmItwvEj8UKOc?p=preview
I have a simple directive called po-datepicker, it displays a datepicker on the screen, but allows the user to type a date manually:
<input type="text" ng-model="model" po-datepicker required />
and this is the directive:
myApp.directive('poDatepicker', function () {
return {
require: ['?^ngModel'],
restrict: 'A',
link: function ($scope, elem, attrs, ctrl) {
var ngModel = ctrl[0];
var picker = elem.datepicker();
picker.on('changeDate', function(e) {
ngModel.$setViewValue(e.date);
...
});
elem.parent().find('button').on('click', function() {
picker.datepicker('show');
});
var changeFn = function(e) {
// Here I have some logic that calls $setViewValue();
};
picker.on('hide', changeFn);
elem.on('keyup blur', changeFn);
}
};
});
this works as expected, but when I try to type a value in the input, it updates the ngModel, changing the variable in the scope, how can I prevent ngModel from being changed in the input?
Here is a plunkr, try manually writing a value and you'll understand what I'm talking.
Actually, after some research, I found a solution for this problem.
What I found on forums and questions is that I needed to unbind the element's events, like this:
elem.unbind('input').unbind('keydown').unbind('change');
But that solution didn't work as expected.
The problem is that I'm currently using Angular 1.2.x, I found out that you need also to set some priority to the directive, such as:
return {
require: ['?^ngModel'],
priority: 1,
...
}
The priority: 1 is needed in this case, because of the priority of some internal Angular.js directives.
Here is an updated plunker with the right priority set up.
Just add 'disabled' to the input http://plnkr.co/edit/xFeAmSCtKdNSQR1zbAsd?p=preview
<input type="text" class="form-control" ng-model="test" po-datepicker required feedback disabled/>
I have an angularjs application that does a bunch of calculations based on inputs from textboxes. I have it working pretty well, but if the user selects the numbers in the input box and deletes them, the result that's based on that number is immediately changed to undefined. In this case, angularjs is TOO fast. From a UX standpoint, I would prefer that the user is free to edit the textbox and only after they have blurred that box will the calculations update.
Is there way to make this happen right on an input field like this:
<input type="text" ng-model="model" custom-magical-directive>
I know I can create my own directive with an isolated scope and only update the parent model when I'm ready, but I'd prefer to keep it clean because if I end up with something like this:
<div custom-isolated-directive ng-model="model">
<input type="text" ng-model="isolatedModel">
</div>
styling is going to be a challenge.
If you don't want the immediate two way binding provided by ng-model, you can leave it out and use a directive to update the model when you want to:
<input type="text" update-on-blur="data.name" />
directive:
app.directive('updateOnBlur', function(){
return {
restrict: 'A',
scope: {
updateOnBlur: '='
},
link: function(scope, element, attr) {
scope.$watch('updateOnBlur', function(newVal, oldVal) {
element.val(newVal);
});
element.on('blur', function() {
scope.updateOnBlur = element.val();
scope.$apply();
});
}
}
})
Here is a demo: http://plnkr.co/dF9JbfPkgRQxWmGp57ap
A $watch function will make sure that programmatic changes are visible in the input. Then, an event handler updates the model on blur.
This should be pretty simple, but for some reason when I have
<div class="file-navigator" ng-controller="FileSystemCtrl">
<input type="file" id="openFile" ng-model="path" ng-change="openFolder()" nwdirectory />
The ng-change doesn't get triggered.
If I use
onchange="angular.element(this).parent().scope().openFolder()"
the onchange event gets triggered, but obviously, that's ugly.
The FileSystemCtrl is defined as a module which I'm importing into my app, it's structured like this.
angular.module('myApp.FileSystemModule',[])
.factory('FileSystemModel',function($rootscope){...})
.controller('FileSystemCtrl',function(){...});
Any ideas why the child doesn't know about it's parent controller? Particularly as the child doesn't have a controller of it's own?
AngularJs doesn't support input with type file. See this issue. And this. Your onchange event is the best option for now.
Another way would be to use a directive taking advantage of $compile to interact with a ng-model:
.directive('path', function($compile) {
return {
restrict: 'E',//<path></path> in your markup
replace: true,
template: '<input type="file" />',
link: function(scope, elem, attrs) {
var textField = $(elem).attr('ng-model', 'something');
$compile(textField)(scope);
$(elem).change(function() {
//do stuff
});
}
};
});
I didn't test it, but it provides you with a get-go.
I know this question has been asked about 100 times (trust me, I've read them all), but I'm having trouble getting focus to go to an input box when the directive does NOT use isolate scope. The scope.$watch doesn't fire when the backing data changes.
Why not just use the one with isolate scope, you ask? Well, my understanding is that you should ONLY use isolate scope if your directive has a template.
The only differences in the directives is:
// works
app.directive('doesFocus', function ($timeout) {
return {
scope: { trigger: '#doesFocus' },
link: function (scope, element) {
scope.$watch('trigger', function (value) {
// sets focus
}
...
// does not work, and in fact when I inspect attrs.doesNotFocus it is undefined
app.directive('doesNotFocus', function ($timeout) {
return {
scope: false,
link: function (scope, element, attrs) {
scope.$watch(attrs.doesNotFocus, function (value) {
// sets focus
}
...
I'm on week 3 of using Angular, so I must be missing some silly semantic issue.
Here is a fiddle illustrating my issue.
http://jsfiddle.net/tpeiffer/eAFmJ/
EDIT
My actual problem was that my real code was like this (hazard of mocking the problem, you sometimes mask the real problem):
<input should-focus="{{isDrawerOpen()}" ... ></input>
but because I was using a function, not a property, I was missing the required ticks
<input should-focus="{{'isDrawerOpen()'}}" ... ></input>
Making this change fixed the problem and my directive can still be like this:
scope.$watch(attrs.shouldFocus, focusCallback(newValue));
END EDIT
Thanks for helping me in my quest for angular excellence!
Thad
Remove {{}} from your HTML. So instead of:
<input class="filter-item" placeholder="Enter filter"
does-not-focus="{{bottomDrawerOpen}}" type="text">
use
<input class="filter-item" placeholder="Enter filter"
does-not-focus="bottomDrawerOpen" type="text">
Then it works with watching attrs.doesNotFocus:
scope.$watch(attrs.doesNotFocus, function (value) {...} );
Fiddle
Your bottom drawer was watching a function isDrawerOpen(), not a property.
Change
scope.$watch('isDrawerOpen()',...);
to
scope.$watch('toggleBottomDrawer',...);