ng-disabled active/inactive - angularjs

http://jsfiddle.net/zjqz6wjL/
I have 3 buttons, when you click on a button they all become disabled.
It would be nice if only the button I click becomes disabled and the other two remain active. When clicking on another button that one becomes disabled and in turn reactivating the previously disabled button back to active state.
<button ng-click="disableClick()" ng-disabled="isDisabled" ng-model="isDisabled">Disable ng-click 1</button>

You can do this :
angular.module('ngToggle', [])
.controller('AppCtrl',['$scope', function($scope){
$scope.btns = [
{name:'1',isDisabled:false},
{name:'2',isDisabled:false},
{name:'3',isDisabled:false}
];
$scope.disableClick = function(btn) {
alert("Clicked!");
angular.forEach($scope.btns,function(_btn){
_btn.isDisabled = false;
});
btn.isDisabled = true;
return false;
}
}]);
With this template :
<body ng-app="ngToggle">
<div ng-controller="AppCtrl">
<button ng-repeat="btn in btns" ng-click="disableClick(btn)" ng-disabled="btn.isDisabled">Disable ng-click {{btn.name}}</button>
</div>
</body>
See here : https://jsfiddle.net/dy7g0snx/
You don't need the ng-model directive here (it was unsed though).
Use your btns as objects
Get it as array
Use ng-repeat directive to loop on it
Pass the btn object in disableClick method
Disable all buttons in the method
Then enable the passed button
EDIT
Inspired by the comment then the answer of Joaozito Polo, here an alternative if you don' want to use objects. It is not recommended in most case but with a use case with only 2 or 3 buttons, non-paramtric, it is acceptable.
In a such situation, you didn't need the $scope.disableClick() thus, no more need the controller too.
Just declare your angular module js-side :
angular.module('ngToggle', []);
And use ng-click then ng-disable directives in content corelations :
<body ng-app="ngToggle">
<button ng-click="disabled = 1" ng-disabled="disabled == 1">Disable ng-click 1</button>
<button ng-click="disabled = 2" ng-disabled="disabled == 2">Disable ng-click 2</button>
<button ng-click="disabled = 3" ng-disabled="disabled == 3">Disable ng-click 3</button>
</body>
Note that I removed the ng-controller directive too, because it will not defined js side now.
See the demo here

You can choose to extract to independent directives. There are two directives: buttonGroup and myButton. In buttonGroup, the property disabledBtnName stores the name of the only disabled button. In ng-repeat, only the button with name disabledBtnName will be disabled. It is easy to be reused, say, in many different pages.
angular.module('ngToggle', [])
.directive('buttonGroup', [function () {
return {
restrict: 'A',
transclude: true,
scope: {},
template:
'<div>' +
'<button ng-repeat="btn in buttons" ng-disabled="btn.name == disabledBtnName" ng-click="disableMe(btn)" ng-bind="btn.text"></button>' +
'<div ng-transclude></div>' +
'</div>',
controller: ['$scope', function ($scope) {
$scope.buttons = [];
this.addButton = function (btn) {
$scope.buttons.push(btn);
};
$scope.disableMe = function (btn) {
$scope.disabledBtnName = btn.name;
};
}]
};
}])
.directive('myButton', [function () {
return {
restrict: 'A',
scope: {
name: '#',
text: '#'
},
require: '^buttonGroup',
link: function (scope, iElement, attrs, btnGroupCtrl) {
btnGroupCtrl.addButton(scope);
}
};
}]);
Simply use it like:
<body ng-app="ngToggle">
<div button-group>
<div my-button name="one" text="Button One"></div>
<div my-button name="twp" text="Button Two"></div>
<div my-button name="three" text="Button Three"></div>
</div>
</body>
Check the online working demo: http://jsfiddle.net/zjqz6wjL/4/

You can store the last clicked button information, and check on ngDisabled:
<button ng-click="click(1)" ng-disabled="lastClicked == 1">Disable ng-click 1</button>
and your action:
$scope.click = function(btn) {
alert("Clicked!");
$scope.lastClicked = btn;
return false;
}
You can see on jsfiddle

Here is what I have managed to do without use of controllers :
<body ng-app="ngToggle">
<div ng-controller="AppCtrl" ng-init = "disabled=0">
<button ng-click = "disabled = disabled == 1 ? 0 : 1" ng-disabled="disabled == 1" ng-model="isDisabled">Disable ng-click 1</button>
<button ng-click="disabled = disabled=== 2 ? 0 : 2" ng-disabled="disabled == 2" ng-model="isDisabled">Disable ng-click 2</button>
<button ng-click="disabled = disabled=== 3 ? 0 : 3" ng-disabled="disabled == 3" ng-model="isDisabled">Disable ng-click 3</button>
</div>
here is the fiddle : http://jsfiddle.net/zjqz6wjL/8/

Related

How to use multiple controller in one directive angularjs?

Is it correct to use multiple controllers like below?
<div ng-if="actionButtonText=='Confirm'" ng-controller="upsrCtrl" ng-controller="pt3Ctrl" ng-controller="spmCtrl">
<button ng-click="checkAnswer()" class="button button-confirm-outline">
{{actionButtonText}}
</button>
</div>
The reason I used these were I make this as footer and the content change dynamically based on different controller.
I'm assuming your ng-if handles the switch on which ng-controller to use. And the ng-clickis the event that triggers the switch. If thats the case just render all 3 blocks only show based on parentCtrl.
<div ng-controller="parentCtrl">
<div ng-if="parentCtrl.actionButtonText=='upsrCtrl'" ng-controller="upsrCtrl">
<button ng-click="checkAnswer()" class="button button-confirm-outline">
{{actionButtonText}}
</button>
</div>
<div ng-if="parentCtrl.actionButtonText=='pt3Ctrl'" ng-controller="pt3Ctrl">
<button ng-click="checkAnswer()" class="button button-confirm-outline">
{{actionButtonText}}
</button>
</div>
<div ng-if="parentCtrl.actionButtonText=='spmCtrl'" ng-controller="spmCtrl">
<button ng-click="checkAnswer()" class="button button-confirm-outline">
{{actionButtonText}}
</button>
</div>
</div>
Providing wrappers of controller may be a way to find your solution. But if you will see it on element level, An element can not carry more then one one controller.
As i can see there is a way To make one controller the main controller and pass another controller as some other parameter. like vm i used in bellow example . Here vm is is the page level controller instance(controller of the page where the element is present). use Isolated scope here to access vm
<div ng-if="actionButtonText=='Confirm'" ng-controller="upsrCtrl">
<button ng-click="checkAnswer()" class="button button-confirm-outline" vm='vm'>
{{actionButtonText}}
</button>
</div>
But the better way i will suggest is To use more then one directive with its separate controllers and use it. It will be some kind of attribute level directive. which will make your purpose solve.
app.directive('dirUp', function() {
return {
controller: function(scope) {
//directive controller
}
};
});
app.directive('dirDown', function() {
return {
controller: function(scope) {
//directive controller
}
};
});
and in html
<div dir-up use-down></div>
Hope it will help you.
Try to use custom directive like below. Take a look on a plunker:
https://plnkr.co/edit/ileyNcaSlJYLc2bCbJeq?p=preview
app.directive('ifController', function factory($compile) {
var handler = {
restrict: 'A',
scope: {
ifController: '#'
},
link: function(scope, element, attrs){
var lastElement = null;
var update = function() {
if (lastElement !== null) {
lastElement.remove();
}
var template = '<div ng-controller="' + scope.ifController + '">'+
'<button ng-click="checkAnswer()" class="button button-confirm-outline">'+
'{{actionButtonText}}'+
'</button>' +
'</div>';
var linkFn = $compile(template);
var content = linkFn(scope);
element.append(content);
lastElement = content;
}
scope.$watch('ifController', update);
}
};
return handler;
});
You can set controller by passing a variable to if-contoller like below:
<div if-controller="{{controller}}">
This will remove previous build of element and compile a new one with a new one controller. Also you can modify this directive to use it as a wrapper to another directive you with to use (just change template).

Why my angular directive doesn't work?

I have a directive that is triggered when clicking on a button. The function inside the directive simply has to change the property value of the field. So what I try to do is to change from 'popover-trigger="blur"' to 'popover-trigger="none"'.
Here is my plunkr: http://plnkr.co/edit/L81fQgi7j1dEtf1QAZJ2?p=preview
or the code is here:
var app = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
app.controller('PopoverDemoCtrl', function ($scope) {
$scope.dynamicPopover = {
content: 'Hello, World!',
templateUrl: 'myPopoverTemplate.html',
title: 'Title'
};
$scope.label = "Please click";
$scope.message = "ON FOCUS trigger a tooltip";
$scope.htmlPopover = "myPopoverTemplate.html";
});
app.directive("changeTrigger", function($compile){
return{
restrict: 'A',
link: function(scope, elm, attrs)
{
elm.bind('click', function(){
var t = document.getElementsByClassName('f')[0].setAttribute('popover-trigger', 'none');
$compile(t);
console.log("Click works");
});
}
}
});
html
<div ng-controller="PopoverDemoCtrl">
<br><br><br>
<p>{{message}}</p>
<input class="f" type="text" value="Click me!" uib-popover-template="htmlPopover" popover-trigger="focus" popover-popup-close-delay="1000" popover-placement="right" required>
<test-directive></test-directive>
<script type="text/ng-template" id="myPopoverTemplate.html">
<div>
<p>Click the button to stop triggering tooltip!</p>
<button change-trigger><b style="color: red">Stop tooltip</b></button>
<div class="label label-success">page</div>
</div>
</script>
</div>
You can't reconfigure the angular-bootstrap Popup element by changing uib-popup-* parameters; but you can bind a scope variable to popup-enable attribute to be able to switch the popup on/off. Add:
<input ... uib-popover-template="htmlPopover" popover-enable="enable" ...>
and
$scope.enable = true;
The problem here is that your button and the input box have different scopes. But you can fix this by retrieving the scope of the field:
var t = document.getElementsByClassName('f')[0];
var scope_ = angular.element(t).scope();
Of course, you need to use $scope.$apply for the scope to correctly handle two-way data binding:
scope_.$apply(function () {
scope_.enable = false;
});
Working Plunkr.

uib-timepicker broken when $compile

I want to use a 'uib-timepicker' inside a popover, so as I read, I need to $compile the html to bind it to angular scope:
app.directive('bsPopover', function($compile) {
return function(scope, element, attrs) {
element.find('#formula-nro').popover({
html : true,
title : '<span>Title</span>',
content : function() {
return $compile($('#formula_form_nro').html())(scope);
// return $('#formula_form_nro').html();
}
});
};
});
If I compile the code, the component brokes, but when I don't, it's shows and behaves correctly, but it is not binded to angular scope.
This is the HTML code of the component:
<div id="formula_form_nro" class="padding-block hide">
.....
<uib-timepicker ng-model="time" minute-step="15" readonly-input="true"> </uib-timepicker>
.....
</div>
The following is the popover button:
<button id="formula-nro" type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="top">f(x)</button>
The button is inside a ng-repeat:
<div ng-repeat="item in items" bs-popover>
It looks like a bug, but I don't know if am I doing well. Maybe there is a workaround for this ..
thanks,

My directive controller function isn't being triggered on ng-click. Angularjs

my directive controller $scope.closeSpinner function isn't being triggered when button ng-click="closeSpinner()" is clicked on the directive template.
AddUsers.Html
<div spinner spinneron="playerSearchSpinnerOn"> </div>
Directive
monopolyMenuModule.directive('spinner', ['spinObj', function (spinObj) {
return {
restrict: "A",
scope:{
spinneron: "="
},
link: function ($scope, elem, attr) {
$scope.$watch('spinneron', function (newValue, oldValue) {
if (newValue != oldValue) {
if (newValue) {
// load spinner, create a model dialog, with a cancel button.
var spinner = spinObj.spin();
var element = angular.element(".modal-content");
element.append(spinner.el);
$("#spinnerDialog").modal('show')
}
else if (newValue == false) {
// close spinner called.
spinObj(false);
}
}
});
},
controller: function($scope)
{
$scope.closeSpinner = function () {
$scope.spinneron = false;
}
},
templateUrl: '/Js/MonopolyMenu/model.html'
}
}]);
Template Html
<div class="modal fade" id="spinnerDialog" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-footer">
<button class="btn btn-success" data-dismiss="modal" ng-click="closeSpinner()">Cancel</button>
</div>
</div>
</div>
Based on the provided Plunkr, it seems to be working just fine. You should make sure your file paths are setup correctly to the template within the directive. Perform a test that it is being called with a console.log or $log.log call (as I have done in the plunk). Also, feel free to add the spinObject code to the provided Plunk.

Angular directive to append or delete a input element with unique id based on button click

I'm new to Angular and am trying to do this the Angular Way. I have a list with several <li> elements created using ng-repeat. In each <li> I have a button that increments a counter and one that decrements the counter and initially one <input type=text>. I want to append or remove a duplicate <input type=text> with a unique id corresponding to whether the increment or decrement button is clicked.
Here is the markup for the portion of my page template I'm working with
<ul class="list">
<li class="item" ng-repeat="resource in resources">
<div class="resource-desc">{{resource.description}}</div>
<img ng-src="{{resource.thumb}}">
<div class="incrementer" ng-controller="CounterCtrl">
<button id='{{$index}}' class="count-btn ion-arrow-up-b" ng-click="increment()" ng-init="count=0">
<span class="ion-plus-round"></span>
</button>
<div id='{{$index}}'class="count-btn count">{{count}}</div>
<button id='{{$index}}' class="ion-arrow-down-b" ng-click="decrement()">
<span class="ion-minus-round"></span>
</button>
</div>
<div id='{{$index}}' class="multi-name-input">
<div class="input_wrapper">
<input type="text" name="{{$index}}resource" required>
<label for="{{$index}}resource">Enter a Name to Display(ie Bay 1)</label>
</div>
</div>
</li>
</ul>
And my Counter controller
'use strict';
angular.module('myapp.controllers', ['ionic', 'ui.bootstrap'])
.controller('CounterCtrl', function($scope) {
$scope.decrement = function() {
$scope.count = $scope.count - 1;
if ($scope.count < 0){
$scope.count = 0;
}
};
$scope.increment = function() {
$scope.count = $scope.count + 1;
};
})
The input markup for the partial I want appended
<div class="input_wrapper">
<input id='{{$index}}' type="text" name="resource{{$index}}" required>
<label for="resource{{$index}}">Enter a Name to Display</label>
</div>
I think my directive should look something like this
.directive('bw-input-append',function($compile){
return {
templateUrl: '../../templates/partials/text_input.html',
transclude: true
link: function(scope, element){
element.click(function(){
element.parent().find('.multi-name-input').append($compile(template)(scope));
});
}
};
});
But I'm really not sure if that's right at all or what options I might need or want in the directive.
I was able to figure out how to write directives for both appending and removing input elements and attached those to their respective increment and decrement buttons on the counter.
Here is the markup for the buttons
<section ng-app="myApp" ng-controller="MainCtrl">
<addinputsbutton></addinputsbutton>
<removeinputsbutton></removeinputsbutton>
<div id="space-for-inputs"></div>
</section>
..and here are the directives.
var myApp = angular.module('myApp', []);
function MainCtrl($scope) {
$scope.count = 0;
}
//Directive that returns an element which adds inputs on click
myApp.directive("addinputsbutton", function(){
return {
restrict: "E",
template: "<button id='{{$index}}' class=\"count-btn ion-arrow-up-b\" ng-click=\"increment()\" ng-init=\"count=0\" addinputs><span class=\"ion-plus-round\">+</span></button>"
}
});
//Directive for adding inputs on click
myApp.directive("addinputs", function($compile){
return function(scope, element, attrs){
element.bind("click", function(){
angular.element(document.getElementById('space-for-inputs')).append($compile("<div class='resource-input'><input id='{{$index}}' type=\"text\" name=\"resource{{$index}}\" required><label for=\"resource{{$index}}\">Enter a Name to Display</label></div>")(scope));
});
};
});
//_______________________________________________________________________
//Directive that returns an element which removes inputs on click
myApp.directive("removeinputsbutton", function(){
return {
restrict: "E",
template: "<button id='{{$index}}' class=\"count-btn ion-arrow-down-b\" ng-click=\"decrement()\" ng-init=\"count=0\" removeinputs><span class=\"ion-minus-round\">-</span></button>"
}
});
//Directive for removing inputs on click
myApp.directive('removeinputs', function(){
return function(scope, element){
element.bind('click', function(){
document.getElementById('space-for-inputs').removeChild(document.getElementById('space-for-inputs').lastChild);
});
};
});
For some reason I couldn't get the 'addinput' and 'removeinput' directives to work in JSFiddle unless I added them to a custom button created from the element directives. But the 'addinput' and 'removeinput' elements worked fine in plain button tags in my application. Here is the JSFiddle in case any one is interested.

Resources