Angular js - Disable toggle switch - angularjs

(using angular and typescript)
I have a toggle switch directive as:
return {
restrict: 'E',
scope: {
ngModel: '=',
onText: '#',
offText: '#',
title: '#',
},
template:
'<label class="switch-light well">' +
' <input type="checkbox" ng-model="ngModel">' +
' <span>' +
' {{title}}' +
' <span class="switch-light-option" ng-class="{ \'switch-light-checked\': !ngModel}">{{offText}}</span>' +
' <span class="switch-light-option" ng-class="{ \'switch-light-checked\': ngModel}">{{onText}}</span>' +
' </span>' +
' <a class="btn btn-primary"></a>' +
'</label>'
};
In my html I am using this as:
toggle-switch ng-model="myValues" on-text="Enabled" off-text="Disabled"
Now I want to disable the above one. How can I do so.
I am pretty new to angular so any inputs would be appreciated.
Thanks

Use:
<toggle-switch
ng-model="switchStatus"
is-disabled="true">
</toggle-switch>
http://jumplink.github.io/angular-toggle-switch/

try adding the link code to your directive :
link: function ($scope, element, attrs) {
$scope.somethingDisabled = true;
};
and in your html part ng-disabled = somethingDisabled
then all you have to do is just add to the link function how and when you want to disabled either by passing it as an directive attr value or in the controller scope.
makes sense?
EDIT2
as per request I did something that would just show a proof of concept...
here is the plunker..
plunker
link: function ($scope) {
$scope.myclick = function(elem){
setTimeout(function(){$scope.disabled = true;},0);
setTimeout(function(){
$scope.disabled=false;
alert('db call done');
},2000);
};
}
I fixed the buggyness code might still be kinda ugly but Ill leave it to you to prettify it... the second timeout is the db call... first on is pushing the disable to the end of the stack so you'll see the animation.
if you want you can also just use !ngModel in the ng-disabled and then change the value of the ngModel when the db call come back..
good luck

I have the same issue and I used disabled attribute:
<toggle-switch label-text="'Enable Internet Cash'" label-position="'top-center'" disabled="MyBankAccount.HasMoney"></toggle-switch>
the disabled attribute receive a Boolean expression. If the disabled attribute has true value it will disable the toogle-switch , in other case it will enable the toggle-switch.
consider that in js file there is $scope.MyBankAccount and $scope.MyBankAccount is json object with HasMoney property.

Related

How to pass tabindex to tags-input node module when using it as nested directive?

I'm using tags input as nested directive in my own directive. I want to pass an arbitrary index as an attribute in my directive like this:
<dp-tags dp-tabindex="3" ng-model="vm.cityModel.dpTags" load="vm.loadTagts" display-field="title"></dp-tags>
This will call the template of my directive which tags input has implemented in it. I'm also set up my directive as I put the related part
here:
scope: {
'load': '&',
'placeHolder': '#',
'serverErr': '=',
'pattern': '#',
'displayField': '#',
'tagTemplate':'#',
'autoCompleteTemplate':'#',
'dpTagLabel':'#',
editDisabled:'#',
dpTabindex: '='
},
and the tags input in my directive as this:
<tags-input type="text"
tabindex="{{dpTabindex}}"
allowed-tags-pattern="{{pattern}}"
on-tag-adding="checkTag($tag)"
display-property="{{displayField}}"
name="tags1"
class=""
ng-required="false"
ng-model="internalTag"
placeholder="{{placeHolder}}"
template="{{tagTemplate}}"
add-on-comma="false"
min-length="2"
ng-disabled="editDisabled"
>
<auto-complete source="load()($query)" template="{{autoCompleteTemplate}}" min-length="2"></auto-complete>
</tags-input>
But this doesn't work where as in my other directives(templates for select/textfield) I have no problem with this method. I really appreciate it if you could help me to fix this problem.
Thanks.
I juts reached to a solution!
I put a listener for keydown and then a counter to count the times I hit the Tab key. When the counter (scope.indexOfTab) becomes equal to the tabindex I set for the tags-input directive, I get the related tag to focus on in tags-input($('tags-input div')), I found it by hitting inspect on the input field, then I add the focus method as bellow:
link(scope, elm, attr, ngModel) {
scope.indexOfTab = 0;
scope.keydown = $(document).on("keydown", function (e) {
if ((e.keyCode || e.which) == 9) {
scope.indexOfTab = scope.indexOfTab + 1;
if (scope.indexOfTab == scope.dpTabindex) {
$('tags-input div').focus();
}
console.log("scope.indexOfTab: " + scope.indexOfTab);
}
});
}

ng-change and ng-focus not working in custom input directive

I'm working on customize a input directive which including a label. I tried several days and refer to some articles.
The only problem is that except ng-change, ng-blur and ng-focus, all the other event work. https://jsfiddle.net/luneyq/mw3oz2pr/
Of course I can bind these three event manually myself and they can work as https://jsfiddle.net/luneyq/bp7f3z1o/
But I really don't know why ng-change, ng-blur and ng-focus don't work. Is there any special on these three event?
Anyone can help on this?
My codes are as below:
<div ng-app="myApp">
<div ng-controller="MainController">
<my-input type="number" name="valueNumber1" ng-model="obj.valueNumber1" label="Age" ng-click="log('click')" ng-change="log('change')" ng-blur="log('blur')" ng-focus="log('focus')" ng-mouseleave="log('mouseleave')"></my-input>
<div id="result"></div>
</div>
The JS:
var app = angular.module("myApp", []);
app.controller('MainController', function($scope, $window){
$scope.obj = {valueNumber1: 10};
$scope.log = function(text) {
document.getElementById("result").innerHTML = text + ':' + $scope.obj.valueNumber1 + "<br>" + document.getElementById("result").innerHTML;
};
});
app.directive('myInput', function() {
return {
require: '^ngModel',
restrict: 'EA',
scope: {
ngModel: '=',
name: '#name',
label: '#label'
},
replace: true,
transclude: true,
priority: 10,
template: '<div>' +
'<label for="{{ name }}">{{label}}</label>' +
'<input id="{{ name }}" ng-model="ngModel" />' +
'</div>',
compile: function(tElement, tAttrs, transclude) {
var tInput = tElement.find('input');
// Move the attributed given to 'custom-input' to the real input field
angular.forEach(tAttrs, function(value, key) {
if (key.charAt(0) == '$')
return;
tInput.attr(key, value);
});
tElement.replaceWith('<div class="cbay-input-div">' + tElement.html() + '</div>');
return;
}
};
});
Thanks in advance.
The issue is that compilation/transclusion/replace don't work the way you think they work (not sure where you made an incorrect assumption).
What is wrong with your code:
1). You are using incorrect attribute name: you should use tInput.attr(tAttrs.$attr[key], value); instead of tInput.attr(key, value);.
2). All the directives specified at my-input are compiled and linked despite your changes to the tElement in compile function. Proof is here - https://jsfiddle.net/fyuz3auc/3/, take a look at the myTest directive and its output in console: it is still applied to the myInput despite any of your effort.
3). You specified scope for your directive. Thus it has an isolated scope, thus anything you've compiled inside it has no access to log function of MainController, that's why your logs aren't working. Here is the fiddle proving that: https://jsfiddle.net/m5tba2mf/1/ (take a look at $scope.log = $scope.$parent.log in link function returned from compile).
In order to solve the second issue I suggest you to try alternative approach - I am using this at my project, and like it very much. The idea is to use terminal in conjunction with extremely high priority and $compile. Here is the updated fiddle, I think it is pretty straightforward what I do there: https://jsfiddle.net/uoat55sj/1/.

AngularJS: Should I observe optional attributes?

Assume I have a directive my-button with an optional attribute disabled. People could use this directive like:
<my-button>Button text</my-button>
or
<my-button disabled="variable">Button Text</my-button>
Should I be watching for a disabled attribute? Could these usages somehow transition from one to the other?
In response to JB Nizet's request for the code in question, here's a clean version of the directive function:
function ButtonDirective() {
var directive = {
link: link,
restrict: 'E',
scope: {
click: '&',
disabled: '=?',
},
template: '<a class="my-button" ' +
'data-ng-class="{\'my-button-disabled\': disabled}" ' +
'data-ng-click="disabled || click()" ng-transclude />',
transclude: true
};
function link(scope) {
if (typeof scope.disabled == 'undefined') scope.disabled = false;
}
return directive;
}
The directive creates an anchor tag styled as a button. It accepts two properties/parameters: click and disabled. The latter is optional. When disabled, the click event should fire when clicked, otherwise the the click event should fire when clicked.
To reiterate: Should I worry about someone somehow adding, removing, or modifying the disabled attribute after the fact? If so, how should I go about it?
After hashing things out with JB Nizet, he counseled me to not worry about the HTML attribute changing.

Select directive not working right in Firefox [duplicate]

I have several multi-selects on a page, each with a bit of logic that fills that multi-select from the server, and I want to wrap each one up into a Directive.
Before trying to wrap these into Directives, I built each as such:
index.html
<select name="groups" ng-model="inputs.groups" ng-change="groupsChanged()" ng-options="g for g in allgroups" multiple></select>
controllers.js
In the first pass, I do my $http calls from here. Yes, I know, not best practices, but I wanted to prove that this works to myself first.
$scope.loadSelect = function(_url) {
$http({
url: _url,
method: 'POST',
data: $scope.inputs,
model: 'all' + _url
}).success(function(data, status, headers, config) {
$scope[config.model] = data;
});
};
// Fill groups
$scope.loadSelect('groups');
// When groups change, reload other select fields that depend on groups
$scope.groupsChanged = function() {
$scope.loadSelect('categories');
$scope.loadSelect('actions');
}
Now I want to migrate this to a Directive. I see two major challenges:
1.) How do I encapsulate the entire set of options (e.g. what is now the "allgroups" model) into the Directive?
2.) Based on initial experiments, I tried to physically build the <select/> into the template, but realized that I have to manipulate the DOM to physically replace name, ng-model, and ng-options. That lead me to the compile attribute, but a.) that feels wrong and b.) setting <select ng-options="x for x in allgroups" /> doesn't actually repeat after it's been inserted into the DOM. Using compile doesn't feel right; what's the right way to approach this?
Here is my first attempt at the Directive looks like this. It doesn't really work, and I think I'm going about it incorrectly:
index.html
<dimension ng-model="inputs.users" alloptions-model="allusers">Users</dimension>
directives.js
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="{{ngModel}}" ng-options="x for x in {{alloptionsModel}}" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
Clearly I haven't even gotten to the server load part yet, but I plan to roll that into a controller in the Directive, with the actual $http call in a service.
I feel like I'm moving down the wrong track. If you have suggestions on how to realign, please help!
The main problem with your directive is that you can't use mustache binding in ngModel and ngOptions directive because they are evaluated directly. You can directly bind to the scoped property (ngModel and alloptionsModel):
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="ngModel" ng-options="x for x in alloptionsModel" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
See this plunkr for a working example.
Edit
As for the compile route, there is nothing wrong with it. It is useful when you need to dynamically create a template which will clearly be your case when you will get to the select's item template.
compile: function(tElement, tAttrs) {
var select = tElement.find('select'),
value = tAttrs.value ? 'x.' + tAttrs.value : 'x',
label = tAttrs.label ? 'x.' + tAttrs.label : 'x',
ngOptions = value + ' as ' + label + ' for x in alloptionsModel';
select.attr('ng-options', ngOptions);
}
// In the HTML file
<dimension ng-model="inputs.users"
alloptions-model="allusers"
label="name">
Users
</dimension>
I've updated the plunkr with the compile function.

AngularJS nested directive $pristine and $dirty settings

I'm having issues with a directive I am writing.
Within the directive's template there is also another element directive.
Essentially the outer directive is a decorator for the inner, adding more functionality..
The issue that I am having is that the $pristine and $dirty values are not being set as I would have expected.
I have amended the fiddle below to demonstrate a similar scenario..
(Code follows:)
HTML
<body ng-app="demo" ng-controller="DemoController">
<h3>rn-stepper demo (3/5)</h3>
Model value : {{ rating }}<br>
<hr>
<div ng-model="rating" rn-stepper></div>
</body>
JS
angular.module('demo', [])
.controller('DemoController', function($scope) {
$scope.rating = 42;
})
.directive('test', function() {
return {
restrict: 'E',
scope: {
ngModel: '=ngModel'
},
template: '<input type="text" ng-model="ngModel"></input>'
};
})
.directive('rnStepper', function() {
return {
restrict: 'AE',
scope: {
value: '=ngModel'
},
template: '<button ng-click="decrement()">-</button>' +
'<div>{{ value }}</div>' +
'<button ng-click="increment()">+</button>' +
'<test ng-model="value"></test>',
link: function(scope, iElement, iAttrs) {
scope.increment = function() {
scope.value++;
}
scope.decrement = function() {
scope.value--;
}
}
};
});
http://jsfiddle.net/qqqspj7o/
The model is shared as expected and when I change the value in either the text input or using the slider, the binding works - however if I update the value in the text input, only the text input is marked as ng-dirty - the element directive itself remains as ng-pristine as does the outer div.
I don't understand why this is and the values are not propagated to the element? Is that expected behaviour - if so, how do I propagate the ng-dirty etc values to the element directive and the outer div..
Note: I can only use Angular v 1.2.x as the code needs to be compatible with IE8.
Thanks in advance..
Generally in directives you should avoid =value binding, and work directly with ngModelController.
This topic is a bit complicated for discussion here, but there are many great tutorias on the web I point you to this one:
using ngModelController it explains basics of working with ngModel and also tells bit about decorators.
When you work directly with ngModel you can set validity and state (dirty/touched/pristine) directly in your code, you can also set model value via $setViewValue().

Resources