I have a button listening for a click event , the idea is to toggle the state when the button is clicked.
The view :
<button ng-click="nextBtnClicked()" ng-disabled="{{state == 1}}" class="btn">Call</button>
The controller :
app.controller('workStation',['$scope',function($scope)
{
$scope.state = 0;
$scope.nextBtnClicked = function()
{
$scope.state = 1;
};
}]
The problem is that I don't see the changes when the button is clicked.I've also tried to execute $apply() but I got the error "Error:[$rootScope:inprog]"
You don't need to use interpolation.
Use:
ng-disabled="state == 1"
Otherwise:
ng-disabled="{{state == 1}}"
Will be evaulated into:
ng-disabled="false"
Which means the ngDisabled directive will be watching a variable named false on the associated scope.
Use
ng-click="state= !state"
This will toggle the state each time you click the button.
and
ng-disabled="state==1"
to disable the button when state is 1.
Related
I'm trying to use angular to change the css class of an element when a user inputs data, both after a button click and in real time as the user is typing in data.
HTML:
<input type="text" class="defaultClass" ng-class="{true: 'errorClass',
false:'defaultClass'}[updateInput()]" ng-model="inputOne">
CSS:
.defaultClass {border: 1px solid #ccc;}
.errorClass {border: 1px solid #FF0000;}
After a button is pressed, the controller checks if the model of the element is blank and if so, makes the function return true and therefore changes the css class in the ng-class to show an error.
$scope.calcButton = function (){
if ($scope.inputOne === "" || $scope.inputOne === undefined) {
$scope.updateInput = function() {
return true;
};
} else {
$scope.updateInput = function() {
return false;
};
}
};
Outside of the button click function, I have the following code in the same controller that should be watching the status of $scope.inputOne and returning true or false based upon the status of the input:
$scope.updateInput = function() {
if ($scope.inputOne === "") {
return true;
} else {
return false;
}
};
And it works fine as long as I don't click the button, but once the value is changed by the button press the controller stops checking if the input field is empty or filled.
This is a problem because I want to have the error messages fade away as the user types in data after a button press that threw errors, but I can't change the css by user input at this point.
Why does it do this? How can I ensure that the controller still keeps track of what's going on in the input field after the button click?
Try like this
ng-class="{'errorClass' : !inputOne,'defaultClass': inputOne }"
or like this
ng-class="!inputOne ? 'errorClass' : 'defaultClass'"
'',null,NaN,undefined,0 etc considered false in JavaScript.
just check model has value or not.
It'll work through two way binding . don't need method for this to check
I have a table with rows that correspond to pipelines a user has created. There is an option to start or stop that pipelines. If a pipeline is running, the corresponding "Start" Button should be disabled, as well as if a pipeline is getting started right now (before the success function of the startPipeline ajax call gets fired). So, whenever a user clicks "start" I set a scope variable starting to true, which should disable the start button until it gets re-enabled in the success function. But ng-disabled doesn't seem to work. Part of my html (starting part, stopping is the same):
<tr ng-repeat="pipeline in pipelines" ng-click="showPipeline(pipeline)" >
<td>{{$index+1}}</td>
<td>{{pipeline.name}}<br/>{{pipeline.description}}</td>
<td>TBD</td>
<td>{{pipeline.running == true ? 'Running' : 'Idle'}}</td>
<td><md-button ng-click="startPipeline(pipeline._id)" class="md-icon-button md-raised" ng-disabled="starting || pipeline.running == true">
and the important parts of my Controller:
$scope.starting = false;
$scope.stopping = false;
$scope.startPipeline = function(pipelineId) {
$scope.starting = true;
console.log("starting pipeline");
restApi.startPipeline(pipelineId)
.success(function(data) {
$scope.starting = false;
...
})
.error(function(data){
$scope.starting = false;
...
});
};
Using ng-show might be the nicer way:
<md-button ng-click="startPipeline(pipeline._id)" class="md-icon-button md-raised" ng-show="starting || pipeline.running">
If you just use the variables starting or pipeline.running, you do not need to compare their values to true or false.
Use var for true and !var for false.
By the way: if the button does not show/hide by setting the value in your controller, inform your app about the changes with $scope.$apply();
I'm using angularJs and xeditables to create a web application.
In this application, I have several xeditable text following each others and the validation is done when pressing enter or clicking outside:
<div ng-repeat="answer in item.answers track by $index">
<input type="radio" name="{{item.label.text}}"> <span editable-text="answer.text" onshow="onShow()" onhide="onClose()" buttons="no" blur="submit" onbeforesave="validateEditableText($data)">{{answer.text || "Edit this text"}}</span>
</div>
My functions onShow() and onClose() are the following :
$scope.onShow = function() {
alert('onShow');
if($scope.hideMenu == true)
$scope.hideMenu = false;
};
$scope.onClose = function() {
alert('onClose');
if($scope.hideMenu == false)
$scope.hideMenu = true;
};
These functions are just changing a boolean to true.
I use this boolean to stop or not the event propagation (It may sounds weird but I need this functionality).
Here is my function which block the event propagation but it won't be necessary for you to fully understand it for the explications:
$scope.blocEventPropagation = function(event) {
if($scope.selectedItem != null){
if($scope.hideMenu && !$scope.selectedItem.dropDownOpen)
event.stopPropagation();
}
};
Actually the problem I have is, when I click on a xeditable text and then I click directly on another the events don't follow the order I want.
The order is onShow() of the first xeditable text when I click on it, onShow() of the second when I directly click on it before closing the other and onClose() of the first.
Me I'd like onShow() of the first when I click on it, onClose() on the first when I click a second one and onShow() of the second.
At this point read all the documentation of xeditable and I didn't found a solution. I tried to use a time-out to wait the other event but it didn't work.
Do you have an idea to change the event order or to limit the call of a function or even another solution that I didn't think about ?
You can have all elements give a separate contribution in hiding the menu:
<div ng-repeat="answer in item.answers track by $index">
<input type="radio" name="{{item.label.text}}"> <span editable-text="answer.text" onshow="{{$scope.hideMenu[$index] = true;}}" onhide="{{$scope.hideMenu[$index] = false;}}" buttons="no" blur="submit" onbeforesave="validateEditableText($data)">{{answer.text || "Edit this text"}}</span>
</div>
And then, hide it if any element is shown:
<div id="menu" ng-hide="{{$scope.hideMenu.indexOf(true) >= 0}}" />
There may be syntax errors, but I hope it clarifies the point.
Finally I found a solution :
$scope.count = 0;
$scope.onShow = function() {
$scope.count ++;
if($scope.hideMenu == true)
$scope.hideMenu = false;
};
$scope.onClose = function() {
$scope.count --;
if($scope.hideMenu == false && $scope.count == 0)
$scope.hideMenu = true;
};
This solution is very ugly but I really think that with my actual knowledge its the better one in this very specific situation. I tried to find a better one but I couldn't.
Indeed, the previous answer works if we use onShow() and onClose() inside a ng-repeat with the $index. But me I use these two functions at different places in my application so I can't have an index.
We are using Backgrid and have discovered that to begin editing a "boolean" (checkbox) cell in Backgrid, you must click twice: the first click is ignored and does not toggle the state of the checkbox. Ideally we would get to the root of what is causing this behavior (e.g. is preventDefault being called) and solve it there, but I at first I tried a different approach with the following extension of BooleanCell's enterEditMode method which seemed like a logical place since it was upon entering edit mode that the checkbox click was being ignored.
Problem is my attempt also toggles the state of the previously edited checkbox. Here is the code.
var BooleanCell = Backgrid.BooleanCell.extend({
/*
* see https://github.com/wyuenho/backgrid/issues/557
*/
enterEditMode: function () {
Backgrid.BooleanCell.prototype.enterEditMode.apply(this, arguments);
var checkbox = this.$('input');
checkbox.prop('checked', !checkbox.prop('checked'));
}
});
The following seems to work:
var BooleanCell = Backgrid.BooleanCell.extend({
editor: Backgrid.BooleanCellEditor.extend({
render: function () {
var model = this.model;
var columnName = this.column.get("name");
var val = this.formatter.fromRaw(model.get(columnName), model);
/*
* Toggle checked property since a click is what triggered enterEditMode
*/
this.$el.prop("checked", !val);
model.set(columnName, !val);
return this;
}
})
});
This is because the render method gets called by Backgrid.BooleanCell's enterEditMode method on click, and said method destroys and re-creates the checkbox as follows but in so doing loses the checked state (after the click) of the original "non-edit-mode" checkbox
this.$el.empty();
this.$el.append(this.currentEditor.$el);
this.currentEditor.render();
A simpler approach:
var OneClickBooleanCell = Backgrid.BooleanCell.extend({
events: {
'change input': function(e) {
this.model.set(this.column.get('name'), e.target.checked);
},
},
});
This bypasses the CellEditor mechanism entirely and just reacts to the input event on the checkbox by updating the model.
I am using ng-focus and ng-blur to show/hide a button. on focus of an input, a button is shown and on blur it is hidden. Show/hide is being performed using ng-show. On click of this button a function gets called.
Live Demo
Issue is that ng-blur us being called first and the button is getting hidden before the click event is fired, hence function which is to be called from that button is never getting called.
I have already fixed it by using setTimeout() but later found that it is not really a good solution. Is there any other way to fix this issue?
use ng-mouseover and ng-mouseleave
change your button to
<button ng-click="click()" ng-show="show||mouseover" ng-mouseover="mouseover=true" ng-mouseleave="mouseover=false">Click to change</button>
demo
why don't you change the $scope.show=false; in the click event of the button.
In other words, remove the blur event, and the click event will be like this.
$scope.click = function(){
alert("fuu")
$scope.text = "We changed it";
$scope.show=false;
}
I think using a bool can help you to determine the state if it's needed to hide or show the button. On mouseover of the button change the bool to determine the execution of blur function.
Try this ways :
HTML :
<div ng-app ng-controller="LoginController">
<div>{{ text }}</div>
<input ng-focus="focus()" ng-blur="blur()"></input>
<button ng-click="click()" ng-show="show==true" ng-mouseover="mouseover()">Click to change</button>
</div>
angularjs :
function LoginController($scope) {
$scope.show=false;
$scope.blurAll = true;
$scope.text = "this thing will change on click";
$scope.focus = function(){
console.log("buu");
$scope.show=true;
}
$scope.blur = function(){
if(blurAll){
console.log("baaa");
$scope.show=false;
}
}
$scope.click = function(){
alert("fuu");
$scope.text = "We changed it";
$scope.show = false;
}
$scope.mouseover = function(){
blurAll = false;
};
}
jsFiddle
use a custom directive which introduce a delay
app.directive('ngBlurDelay',['$timeout',function($timeout){
return {
scope:{
ngBlurDelay:'&'
},
link:function(scope, element, attr){
element.bind('blur',function(){
$timeout(scope.ngBlurDelay,200);
});
}
};
}])