ng-disabled not working on $scope variable - javascript

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();

Related

Angular ng-if not responding as expected

I have li elements that have an ng-if statement that is tied to a checkbox. If I physically check the checkbox, the ng-if responds as expected. However, if I check or uncheck the checkbox via JavaScript, the checkboxes get checked or unchecked as expected, but the ng-if does not respond. Is this working as it should? Is there a better way to do this?
Here are my code samples: "[]" = "<>"
HTML - Part 1
[li id="homebutton" ng-if="homechecked != true" onclick="homeclicked()"][a ng-href="/"][img src="images\Neck01Home.png" alt="Home" /][/a]
[li id="thebandbutton" ng-if="homechecked===true" onclick="thebandclicked()"][a ng-href="/theband/"][img src="images\Neck01TheBand.png" alt="The Band" /][/a]
HTML - Part 2
[label class="menucontroller"]Home2: [input class="menucontroller" id="homecb" type="checkbox" ng-model="homechecked" ng-init="homechecked=true" /][/label][br /]
[label class="menucontroller"]TheBand2: [input class="menucontroller" id="bandcb" type="checkbox" ng-model="thebandchecked" /][/labe][
[label class="menucontroller"]Gallery2: [input class="menucontroller" id="gallerycb" type="checkbox" ng-model="gallerychecked" /][/label][br /]
JavaScript:
window.onload = function () {
}
function homeclicked() {
document.getElementById('homecb').checked = true;
document.getElementById('bandcb').checked = false;
document.getElementById('gallerycb').checked = false;
}
function thebandclicked() {
document.getElementById('homecb').checked = false;
document.getElementById('bandcb').checked = true;
document.getElementById('gallerycb').checked = false;
}
function galleryclicked() {
document.getElementById('homecb').checked = false;
document.getElementById('bandcb').checked = false;
document.getElementById('gallerycb').checked = true
}
you're doing it wrong, ng-if does not trigger because you only manipulate the checked and unchecked of the check box(using javascript) and not the ng-model, dont try to use javascript to do that, instead do it on your angular controller.
Controller:
$scope.homeclicked = function() {
$scope.homechecked = true;
$scope.thebandchecked = false;
$scope.gallerychecked = false;
};
ng-model on checkbox inputs handles checked and unchecked of it, also there is a native directive https://docs.angularjs.org/api/ng/directive/ngChecked for handling of check and uncheck.
Do it in proper angular way.
Move the functions inside your controller. Call them via ng-click. Let the functions change the scope variables which are bound to check boxes.
<li id="homebutton" ng-if="homechecked != true" ng-click="homeclicked()">
In the mean time inside your scope...
$scope.homeclicked = function {
$scope.homechecked = true;
$scope.thebandchecked = false;
$scope.gallerychecked = false;
}
If you really really want to disregard my advice and go ahead with what you have, which is by the way very bad, you can add this line inside your functions: angular.element(document.getElementById('homecb')).$scope().$apply(); This is again very bad and should totally be avoided.
Use
$scope.$apply();
It will run the digest loop and your ng-if will work as u expect.

Controller stops updating value after the value is changed

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

How to change x-editable event order?

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.

Model changes not updating the view

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.

jQuery validation with submit button disabled

I made some sort of form validation. User can input name of group and group description. With jQuery I'm validating if group name is empty or not, if empty submit button should be disabled. Now I have problems with disabling submit button. If I click on input tag where group name is, then validation is ok, and submit button is disabled, but if I just click on submit button, without touching anything else, then jQuery skip validation and fires submit button although name of group is empty.
I tried setting input tag in focus with jQuery but it only works if I actually click on that input tag.
Submit button is 'saveGroup' button.
Can someone tell me how to invoke click event on this input tag, or maybe I can use some other validation tehnique.
<div class="newGroupDiv">
<label>Title: </label><input type="text" id="groupTitle" onblur="checkTitle();"><br>
<label>Description:</label><br>
<textarea id="groupDescription"></textarea><br><br>
<button id="saveGroup">Save</button>
<button id="cancelGroup">Cancel</button>
<label id="groupError"></label>
</div>
---------------------------------------------------------------------------------
$("#saveGroup").click(function(){
var variable = checkTitle();
if(variable == true){
if($("#groupError").html() == ""){
$(".columns").append('<ul class="'+ $("#groupTitle").val() +'"><li class="naslov">'+ $("#groupTitle").val() +'</li></ul>');
$("ul").sortable({containment : 'document',
tolerance: 'pointer',
cursor: 'pointer',
revert: 'true',
opacity : 0.6,
connectWith : "ul",
placeholder: 'border',
items : 'li:not(.naslov)',
start : function(){
check = false;
$(".readContent").fadeOut(300);
}, stop : function(){
check = true;
}}).disableSelection();
$.post("addGroup.php", {'title' : $("#groupTitle").val(), 'description' : $("#groupDescription").val(),
'color' : $("#colorHex").html(), 'color2' : $("#colorHex2").html()}, function(){
window.location.reload();
});
}
}
});
--------------------------------------------------------------------------------
var checkTitle = function(){
$.post("checkTitle.php", {'title' : $("#groupTitle").val()}, function(data){
if(data == 'exist') $("#groupError").html("Group already exists");
if(data == 'no title') $("#groupError").html("Group title can't be empty");
else if(data == 'ok') $("#groupError").html("");
});
return true;
}
With this 'variable' I tried to accomplish some sort of callback wait, so when this variable gets result from function it should continue with rest of code, but I'm not sure if it works.
You would be better of switching the way you do things here. First of, as I said, make sure you do the "isEmpty" check without performing any ajax calls. Javascript is perfectly capable of doing so itself.
Secondly, instead of checking the HTML inside your element, you'd be better of checking the result of your checkTitle() function. Because there might be a slight possibility the if($("#groupError").html() == ""){ fails because there is still some HTML detected.
The above comments result in this javascript:
function checkTitle() {
$groupTitle = $('#groupTitle').val();
if($groupTitle == "") {
$("#groupError").html("Group title can't be empty");
return false;
} else {
$.post("checkTitle.php", {'title' : $groupTitle }, function(data){
if(data == 'exist') {
$("#groupError").html("Group already exists");
return false;
} else if(data == 'ok') {
$("#groupError").html("");
return true;
}
});
}
}
Now the result of the checkTitle() function can be used in your final check that you perform onBlur and onClick. Let's continue with your HTML:
<div class="newGroupDiv">
<label>Title: </label>
<input type="text" id="groupTitle" onblur="checkTitle();"><br>
<label>Description:</label><br>
<textarea id="groupDescription"></textarea><br><br>
<button id="saveGroup">Save</button>
<button id="cancelGroup">Cancel</button>
<label id="groupError"></label>
</div>
Just a little suggestion is to use a div instead of a label to show your groupError in, I understand right now this is for demo purposes only so it's just a little sidenote.
I'm not 100% possitive this solution will work, however, what I think is causing the issue is the default behaviour of the button you're using. Since the script is completely relying on the ajax call, my guess is that you have to prevent the default from happening as such:
$('#saveGroup').click(function(e) {
e.preventDefault();
});
You could give the script below a shot, hopefully it works. I can't test it because of the ajax calls. But I'll make a jsFiddle with some test data in a minute:
$("#saveGroup").click(function(e){
e.preventDefault();
var formValidation = checkTitle();
// formValidation is only true in case no errors occured
// Therefor making your #groupError check useless
if(formValidation == true) {
// Reset the #groupError html content
$('#groupError').html('');
// insert your other jQuery code here
}
});
a jsFiddle: http://jsfiddle.net/8bJAc/
As you can see onBlur the data is checked (please not there's a random factor that simulates true/false for your ajax call) and after submitting you can see either a success or error message.

Categories

Resources