I'm trying to add a single disabled="disabled" to a button, to block the element while the it is creating a server requests, however, for some reason the documentations information is not working for me, so my case is:
HTML:
<button ng-disabled="isDisable" ng-click="submit()">Submit</button>
JS (into my controller):
$scope.isDisable = false;
$scope.submit = function() {
$scope.isDisable = true;
//$http request....
something.sucess(function(data) {
$scope.isDisable = false;
};
};
for some reason my logic is not working.
Any ideas?
You don't need the {{}} as it's not an expression.
<button ng-disabled="isDisable" ng-click="submit()">Submit</button>
EDIT
If this is a form then on the form tag do ..
<form name="aForm" novalidate ng-submit="submit()">
then submit button
<button type="submit" ng-disabled="isDisable">Submit</button>
Related
What am I trying?
On button clicking showing the progress bar and hiding the button that was clicked.
Problem
Button is not hiding and image is not showing. I inspected the element and I can confirm that the image is given correct url.
My AngularJs Html is below
<form ng-submit="doLogin();" novalidate name='loginForm'>
<input type="text" name="EmailAddress" ng-model="credentials.EmailAddress" required/>
<button type="submit" ng-disabled="loginForm.$invalid" ng-show="{{RegisterShow}}">
Login
</button>
<img ng-src="{{imgProcessingPath}}" ng-show="{{imgProcessingShow}}">
</form>
Controller is below
myApp.controller('LoginController', ['$scope',
function($scope) {
$scope.imgProcessingPath = appUrl + "Images/ajax-loader.gif";
$scope.imgProcessingShow = false;
$scope.RegisterShow = true;
angular.extend($scope, {
doLogin: function() {
$scope.imgProcessingShow = true;
$scope.RegisterShow = false;
var data = {
"EmailAddress": $scope.credentials.EmailAddress
};
userModel.doLogin(data).then(function(response) {
$scope.imgProcessingShow = false;
$scope.RegisterShow = true;
},function(response) {
$scope.imgProcessingShow = false;
$scope.RegisterShow = true;
});
}
});
}
]);
Am I missing anything?
try removing the curly braces for ng-show in html file!
ng-show="RegisterShow"
alternatively you can also use
ng-if="RegisterShow"
ng-show should not have an expression, it acts like model variable,
Change it as,
<button type="submit" ng-disabled="loginForm.$invalid" ng-show="RegisterShow">
also
<img ng-src="{{imgProcessingPath}}" ng-show="imgProcessingShow">
I am posting this as an answer as I don't have the rep to comment.
Remove the brackets inside ng-show.
<img ng-src="{{imgProcessingPath}}" ng-show="imgProcessingShow">
I have created an angular form that displays input validation errors received from the server. My solution works fine except for one small issue.
If I submit the form with no value, after the page loads, I am receiving the correct response from my server i.e. 422, but the validation error is not displayed. If I then start typing a value in the input the validation error flashes and disappears.
I am almost certain that it has something to do with my directive, but I'm not sure how to fix it. This is my current directive code:
var appServices = angular.module('webFrontendApp.directives', []);
appServices.directive('serverError', function(){
return {
restrict: 'A',
require: '?ngModel',
link: function(scope,element,attrs,ctrl){
element.on('change keyup', function(){
scope.$apply(function(){
ctrl.$setValidity('server', true);
});
});
}
};
});
I think the issue is with the element.on('change keyup'.... section of this code. That's why the error message flashes when I start typing. Also when I change this to 'change' instead of 'change keyup', the error message is displayed permanently when I start typing.
Does anybody have an idea of how I can display the error message even if I did not type any value into the input before submitting it the first time?
UPDATE AS PER COMMENT
Here is my form:
<form ng-submit="create(memberData)" name="form" novalidate>
<div class = "row form-group" ng-class = "{ 'has-error' : form.email.$dirty && form.email.$invalid }">
<input type="text" ng-model="memberData.email" placeholder="janedoe#mail.com" name="email" class="col-xs-12 form-control" server-error>
<span class="errors" ng-show="form.email.$dirty && form.email.$invalid">
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
<span ng-show="form.email.$error.server">{{errors.email}}</span>
</span>
</div>
<div class="row">
<button type="submit" class="btn btn-danger col-xs-12">Join Private Beta</button>
</div>
</form>
And my controller:
$scope.memberData = {};
$scope.create = function() {
var error, success;
$scope.errors = {};
success = function() {
$scope.memberData = {};
};
error = function(result) {
angular.forEach(result.data.errors, function(errors, field) {
$scope.form[field].$setValidity('server', false);
$scope.errors[field] = errors.join(', ');
});
};
BetaMember.save({ beta_member: { email: $scope.memberData.email || "" }}).$promise.then(success, error);
};
Since the form itself doesn't have a $setValidity method, because doens't have an ng-model, and assuming that the server error is not referred to a single field ( in this case a $setValidity method is preferred ), I think that the simplest solution could be this one:
Create a form with some random validation ( this one simply needs at least the username ) and a div that can display a custom server error.
<div ng-controller="AppCtrl">
<form novalidate name="createForm">
<div class="inputWrap">
<input ng-model="name" name="name" type="text" required placeholder="John Doe">
<span ng-if="createForm.name.$dirty && createForm.name.$invalid">
Some kind of error!
</span>
</div>
<div ng-if="serverError">
{{ serverError.message }}
</div>
<input
value="Join Private Beta"
ng-disabled="createForm.$invalid || serverError"
ng-click="create()"
type="button">
</form>
</div>
Then in your controller you can add the create method that deal with YourService ( should return a promise ) and if the response is failure you can create a simple object with a custom server error message inside which will also be usefull to disable the form button, if you need.
var AppCtrl = function($scope, YourService){
// Properties
// Shared Properties
// Methods
function initCtrl(){}
// Shared Methods
$scope.create = function(){
YourService.makeCall().then(function(response){
// Success!
// Reset the custom error
$scope.serverError = null;
}, function(error){
// Do your http call and then if there's an error
// create the serverError object with a message
$scope.serverError = {
message : 'Some error message'
};
})
};
// Events
// Init controller
initCtrl();
};
AppCtrl.$inject = [
'$scope',
'YourService'
];
app.controller('AppCtrl', AppCtrl);
I mean it's very simple snippet here, I just wanted to bring an example. Nothing to complex, but you can scale this to something more.
It seems that there was an extremely simple workaround. Since I had the filter form.email.$dirty in my view, the error would not be displayed if the user clicked submit without clicking on the form first.
After removing form.email.$dirty and only having form.email.$invalid, it works perfectly. I think this is sufficient in my case, as this validation is dependant on a server response and will not be triggered before the form is submitted. The error object is also cleared up in my controller ensuring that the page does not load an error when it's first loaded.
I am trying to show a Validation Summary, a Div on top of the page with all the Validation error messages in angularjs, on form submit.
I am using the below logic to show/ hide the top div with validation messages,
<div class="alert alert-error" ng-show="submitted && myForm.$invalid">
</div>
I am setting the variable submitted to true on save button click. It's working Okay the first time, but after the first submission, if enter the value for the input field(required field) and clear it, it's kicking off the validation(the top div shows).
Is there a way to show the validation div, only on the submit of the form and not when the user clears the input field ?
UPDATE
$scope.save = function (myForm) {
$scope.submitted = true;
if (myForm.$invalid) {
return;
}
$scope.submitted = false;
}
Thanks !
Hmm one way to do it would be to watch the FormController's property $dirty and $setPristine() method, and use a variable hasError to show the error or not.
See this plunker as an example
JAVASCRIPT
controller('AppController', ['$scope', function($scope) {
$scope.hasError = false;
$scope.$watch('theForm.$dirty', function() {
$scope.hasError = false;
$scope.theForm.$setPristine();
});
$scope.save = function() {
$scope.hasError = $scope.theForm.$invalid;
if($scope.hasError) {
// perform error routine
} else {
// perform save routine
}
};
}]);
HTML
<body ng-controller="AppController">
<div class="error" ng-show="hasError">This is an error</div>
<form name="theForm" ng-submit="save()" novalidate>
<input type="text" name="text1" ng-model="text1" required>
<input type="text" name="text2" ng-model="text2" required>
<button type="submit">Submit</button>
</form>
</body>
Make sure you are setting submitted to false upon display of your validation div else it'll show up after each additional validation call.
$scope.save = function (myForm) {
$scope.submitted = true;
if (myForm.$invalid) {
$scope.submitted = false;
return;
}
}
Am quite new to AngularJS. The issue is i have a form with two fields- name and profile pic as shown in the code below. I am using ng-upload (https://github.com/twilson63/ngUpload). I want the 'Save' button to work only if either field is dirty and the upload isn't happening currently so that multiple post requests are not triggered on the user clicking on the 'Save' button. But looks like, $dirty works fine with the 'name' field but not with the 'profile pic' field. Am i just missing something? How to go about it keeping it as simple as possible for a beginner of AngularJS. Any help would be appreciated.
//Code
<form id='picUpload' name='picUpload' ng-upload-before-submit="validate()" method='post' data-ng-upload-loading="submittingForm()" action={{getUrl()}} data-ng-upload='responseCallback(content)' enctype="multipart/form-data">
<input type="text" name="name" data-ng-model="user.name" maxlength="15" id="user_screen_name" required>
<input type="file" name="profilePic" data-ng-model="user.profilePic" accept="image/*">
<div class="form-actions">
<button type="submit" class="btn primary-btn" id="settings_save" data-ng-disabled="!(picUpload.name.$dirty|| picUpload.profilePic.$dirty) || formUploading">Save changes</button>
</div>
</form>
//In my JS code
$scope.submittingForm = function(){
$scope.formUploading = true;
}
Regards!
I made a directive ng-file-dirty
.directive('ngFileDirty', function(){
return {
require : '^form',
transclude : true,
link : function($scope, elm, attrs, formCtrl){
elm.on('change', function(){
formCtrl.$setDirty();
$scope.$apply();
});
}
}
})
I haven't used ng-upload before, but you can use onchange event of input element. onchange event is fired whenever user selects a file.
<input type="file" onchange="angular.element(this).scope().fileNameChanged(this)" />
Javascript :
var app = angular.module('MainApp', []);
app.controller('MainCtrl', function($scope)
{
$scope.inputContainsFile = false;
$scope.fileNameChanged = function(element)
{
if(element.files.length > 0)
$scope.inputContainsFile = true;
else
$scope.inputContainsFile = false;
}
});
So now you can check if inputContainsFile variable is true along with dirty check of name field
I know you're not supposed to put your display logic inside of a controller and I'm struggling with the proper AngularJS way to approach this.
I'm presenting forms inside modals. I'm using Zurb Foundation's reveal for the modal.
Markup:
<div class="button" ng-click="modalAddWidget">Add Widget</div>
<div id="modalAddWidget" class="reveal-modal">
<h6>New Widget</h6>
<form>
<fieldset>
<legend>Widget Name</legend>
<input type="text" ng-model="ui.add_widget_value" />
</fieldset>
<div class="small button right" ng-click="addWidget()">Add Widget</div>
<div class="small button right secondary" ng-click="addWidgetCancel()">Cancel</div>
</form>
</div>
Controller:
...
$scope.modalAddWidget = function() {
$("#modalAddWidget").reveal();
}
$scope.addWidget = function() {
$scope.myobject.widgets.push({"name": $scope.ui.add_widget_value});
$scope.ui.add_widget_value = '';
$('#modalAddWidget').trigger('reveal:close');
}
$scope.addBudgetCancel = function() {
$scope.ui.add_widget_value = '';
$('#modalAddWidget').trigger('reveal:close');
}
...
Note: $scope.ui is an object I am using to store UI values that shouldn't be bound to my object until the user actually clicks "Add Widget"
$scope.myobj is where my data is stored.
Foundation's $("#modalAddWidget").reveal(); function presents the modal overlay.
Since I shouldn't be putting my display code inside the controller, what is the proper way to approach this?
You don't want to manipulate the DOM (or even reference it) from your controllers.
A directive is best here.
app.directive('revealModal', function (){
return function(scope, elem, attrs) {
scope.$watch(attrs.revealModal, function(val) {
if(val) {
elem.trigger('reveal:open');
} else {
elem.trigger('reveal:close');
}
});
elem.reveal();
}
});
then in your controller:
$scope.modalAddWidget = function (){
$scope.ui = { add_widget_value: '' };
$scope.showModal = true;
};
$scope.addWidget = function (){
$scope.myobject.widgets.push({"name": $scope.ui.add_widget_value});
$scope.ui.add_widget_value = '';
$scope.showModal = true;
};
And in your HTML
<div class="button" ng-click="modalAddWidget()">Add Widget</div>
<div id="modalAddWidget" class="reveal-modal" reveal-modal="showModal">
<h6>New Widget</h6>
<form name="addWidgetForm" ng-submit="addWidget()">
<fieldset>
<legend>Widget Name</legend>
<input type="text" name="widgetValue" ng-model="ui.add_widget_value" required />
<span ng-show="addWidgetForm.widgetValue.$error.required">required</span>
</fieldset>
<button type="submit" class="small button right">Add Widget</button>
<div class="small button right secondary" ng-click="showModal = false;">Cancel</div>
</form>
</div>
Basically you'd set a boolean in your scope to show and hide your modal. (I'm not sure of reveal modal's open/close mechanism, so I'm guessing in my code above).
ALSO: I went through the effort of adding some validation in there.