Angularjs - ng-disabled default value - angularjs

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

Related

Angular binding does not work in data- attribute

I am using some css html template that comes with many html components and with lots of data-attributes for various things. For example for slider it has something like
<div class="slider slider-default">
<input type="text" data-slider class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-value="{{ slider }}" data-slider-selection="after" data-slider-tooltip="hide">
</div>
Here I am trying to bind the value
data-slider-value="{{ slider }}"
But it's not working. Variable 'slider' is set in the $scope as:
$scope.slider = 80;
Same value 80 shows up right when I bind it as:
<h4>I have {{ slider }} cats</h4>
I have also tried
ng-attr-data-slider-value="{{ slider }}"
It didn't work.
Update
The directive has something like this
function slider() {
return {
restrict: 'A',
link: function (scope, element) {
element.slider();
}
}
};
where element.slider(); calls the code in bootstrap-slider.js (from here) for each of the sliders.
I played with this for a while, and came up with a few options for you. See my Plunkr to see them in action.
Option 1: No need to update the scope value when the slider changes
This will work with the HTML from your question. The following is what you should change the directive code to.
app.directive('slider', function slider() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
attrs.$observe('sliderValue', function(newVal, oldVal) {
element.slider('setValue', newVal);
});
}
}
});
Option 2: Two way binding to the scope property
If you need the scope property to be updated when the slider handle is dragged, you should change the directive to the following instead:
app.directive('sliderBind', ['$parse',
function slider($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var val = $parse(attrs.sliderBind);
scope.$watch(val, function(newVal, oldVal) {
element.slider('setValue', newVal);
});
// when the slider is changed, update the scope
// property.
// Note that this will only update it when you stop dragging.
// If you need it to happen whilst the user is dragging the
// handle, change it to "slide" instead of "slideStop"
// (this is not as efficient so I left it up to you)
element.on('slideStop', function(event) {
// if expression is assignable
if (val.assign) {
val.assign(scope, event.value);
scope.$digest();
}
});
}
}
}
]);
The markup for this changes slightly to:
<div class="slider slider-default">
<input type="text" data-slider-bind="slider2" class="slider-span" value="" data-slider-orientation="vertical" data-slider-min="0" data-slider-max="200" data-slider-selection="after" data-slider-tooltip="hide" />
</div>
Note the use of the data-slider-bind attribute to specify the scope property to bind to, and the lack of a data-slider-value attribute.
Hopefully one of these two options is what you were after.
I use .attr and it works for me. Try this:
attr.data-slider-value="{{slider}}"

AngularJS prevent ngModel sync

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/>

AngularJS: how to compile form in a directive

I'm trying to create a custom directive that set 'required' and 'disabled' attributes to the element (form input). The directive gets this data from the scope object. But clearing of required field doesn't set my form to invalide state. I think it's about form compilation after changing the attribute. I tried to do that but got an infinite loop :(
How to compile my form correctly?
Here is plunker
You could just use ng-disabled and ng-required, instead of adding the attributes in a directive.
<div>
<label for="username">username2</label>
<input ng-model="data.account.username2"
ng-disabled="paintData['data.account.username2'] == 'RO'"
ng-required="paintData['data.account.username2'] == 'R'" />
</div>
Alternatively, you could define a directive template that uses ng-disabled and ng-required, and replace the original element with it:
.directive('metaValidate', function($compile) {
return {
restrict: 'A',
replace: true,
scope: {
model: '=',
paint: '='
},
template: '<input ng-model="model" ng-disabled="readonly" ng-required="required"/>',
link: function(scope, element, attrs) {
scope.required = scope.paint[element.attr('model')] === 'R';
scope.readonly = scope.paint[element.attr('model')] === 'RO';
}
};
});
Then, use it like this:
<input model="data.account.username2" meta-validate paint="paintData"/>
I prefer the first approach, because it can respond to changes to paintData. But, you have to repeat the property name several times.
If you want to try this code, here is an update of your Plunker.
Recompiling the element could work, but in order to avoid the infinite loop you need to first remove the meta-validate attribute (which would cause yet more compiling etc):
/* At the end of the directive's link function */
attrs.$set('metaValidate', undefined);
$compile(element)(scope);
See, also, this short demo.

AngularJS detect checkbox value change in directive

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?

Angular.js child input element not getting parents scope

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.

Resources