AngularJS conditional class not working - javascript

I have a register function in my controller:
$scope.register = function() {
User.register($scope.user)
.success(function(data) {
if(data.success) {
$scope.stage = false;
} else {
$scope.message = true;
}
});
}
I then have this HTML:
<div class="form-group" ng-class="{ hidden: stage }">
<label for="token">Confirmation Token</label>
<input type="text" class="form-control" placeholder="Enter the token sent to your phone" ng-model="user.token" required>
</div>
Typically in jQuery I'd update the DOM by removing the class hidden if data.success. Here I've used ng-class to conditionally apply or remove a class, but it seems it's not working.
I want the class to be there by default, and then want it to be removed if data.success
What am I doing wrong here?

You need to set stage to some truthy value in your controller if you want the class to be applied.
$scope.stage = true;
User.register($scope.user)
...
And if all you're aiming to do it show/hide the element, you could use ng-show or ng-hide instead of ng-class (but you'd still need to set stage to true):
<div class="form-group" ng-show="stage">

Try something like this:
<div class="form-group" ng-class="{true: 'hidden'}[stage]">

Related

Add class dynamically from controller

I'm trying to add a class to my element based on whether it's required and empty field. Not sure what I'm doing wrong. My console.log is getting printed but the class is not assigned.
This is my html
<div ng-repeat="supplier in vm.exportSuppliers" class="row">
<div class="col-xs-5">
<label ng-show="vm.exportSuppliers[$index].exportSupplier" class="control-label" for="es{{$index}}+Ref">Agreement Reference *</label>
<label ng-hide="vm.exportSuppliers[$index].exportSupplier" class="control-label" for="es{{$index}}+Ref">Agreement Reference</label>
<input class="form-control" id="es{{$index}}+Ref" type="text"
ng-model="supplier.agreementReference" ng-change="vm.addExportSupplier()"
ng-blur="vm.requiredField('es'+$index+'+Ref')"
ng-required="vm.exportSuppliers[$index].exportSupplier">
</div>
</div>
and my function to make sure field is required and not filled in
vm.requiredField = requiredField;
function requiredField (id) {
if($scope.vm.exportSupplier.form.$error.required) {
for (var i = 0; i < $scope.vm.exportSupplier.form.$error.required.length; i++) {
if ($scope.vm.exportSupplier.form.$error.required[i].$$attr.id == id) {
console.log('invalid required field');
var myEl = angular.element( document.querySelector( id ) );
myEl.addClass('top40');
}
}
}
}
What's wrong with my addClass?
Have a look at the below question. I think you could improve your approach by making use of the ternary operators in ng-class.
angular ng-class if-else expression
You can add conditional classes by using ng-class and form properties provided by angularjs
You need to add "name" attribute on form and specify novalidate on it
<input class="form-control" id="es{{$index}}+Ref" type="text"
name="inputName"
ng-class="{'error-class': formName.inputName.$invalid && formName.inputName.$touched}"
ng-model="supplier.agreementReference" ng-change="vm.addExportSupplier()"
ng-required="vm.exportSuppliers[$index].exportSupplier">
I think this will solve your purpose. No need to write blur function in controller.
There are two ways to handle this situation.
Option 1:
<div ng-class="{'class1': obj.success, 'classB': obj.error}"></div>
Option 2:
<div class="{{obj.classes}}"></div>
The only problem with this approach is that updating the template could become an issue. Sometimes the controller may not update the template. If that is the case, use $scope.$apply(); after the change has been made.

angular js ng-hide in real time doesn't work

I have a snippet of html which I'd like to hide if a variable $scope.city is empty html:
<div class="col-lg-12" **ng-hide="{{city === ''}}"**>
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>
<div class="col-lg-8">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">City#</span>
<input type="text" **ng-model="city"** class="form-control" placeholder="Username" aria-describedby=" basic-addon1">
</div>
</div>
even though they are bound the element does not hide in real time, only if I go to that page with already empty $scope.city variable , there is a one more variable city which comes from varService (I use it to share variable between multiple controllers) here is Angular Code:
app.controller('forecastController', ['$scope','varService','$http', function($scope,varService,$http){
$scope.$watch('city', function() {
varService.city = $scope.city;
});
$scope.city = varService.city;
$scope.numOfDays = 2;
$scope.days = 2;
$scope.$watchGroup(['days', 'city'], function() {
$http.get('http://api.openweathermap.org/data/2.5/forecast?q='+$scope.city+'&mode=json&appid=e652a2c384655ea24f5b12d2fb84c60f&cnt='+$scope.days+'&units=metric')
.then(function(data) { $scope.forecast = data; });
});
}]);
so how do I make ng-hide work in real time as my $scope.city changes ? Thanks.
Instead of
ng-hide="{{city === ''}}"
Write it like this
ng-hide="city.length===0"
city is already bound to $scope in your controller, and ng-hide/ng-show expects an expression. so you don't need to use the double curly brackets({{}}) to evaluate it to true or false, just provide the expression as as like so "city.length===0".
try this;
ng-hide="city == ''"
Change your code use ng-if instead of ng-hide, because ng-if does not create element
<div class="col-lg-12" ng-if="!city.length">
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>
OR
<div class="col-lg-12" ng-hide="city.length">
<h1>{{forecast.data.city.country}} ,{{forecast.data.city.name}} </h1>
<h2>Forcast for : {{city}}</h2>
</div>

change css class on click in angularJs

I am trying to change the CSS class of a div element on click. Below is the code I am trying.
'input-large' should be active by default.
'input-large input-active' should become active on click on username and becomes inactive on clicking somewhere else.
<div class="input-large">
<label class="input-label">Username</label>
<input class="input-field" type="text">
</div>
<div class="input-large input-active">
<label class="input-label">Username</label>
<input class="input-field" type="text">
</div>
Please let me know how to change the DIVs on click
please use ng-click and ng-blur
follow the snippet in :
http://jsfiddle.net/atXAC/11/
<div ng-controller="MyCtrl">
<div ng-class="{'active':hasFocus==true,'inactive':hasFocus==false}">Enter your Name here</div>
<input type="text" ng-model="user.name" ng-click="hasFocus=true" ng-customblur="onBlur()" required id="name"/>
</div>
here goes your js
var myApp = angular.module('myApp', []);
myApp.directive('ngCustomblur', ['$parse', function($parse) {
return function(scope, element, attr) {
var fn = $parse(attr['ngCustomblur']);
element.bind('blur', function(event) {
scope.$apply(function() {
fn(scope, {$event:event});
});
});
}
}]);
function MyCtrl($scope) {
$scope.onBlur = function(){
$scope.hasFocus = false;
}
}
please adapt it for your form.. its working
another approach can be to append the css class in onClick handler in your controller.

AngularJS - form validation, v 1.4.8

This is my first time using AngularJS, and the form validation is making me question my sanity. You would think this would be the easy part, but no matter how many ways I've tried Googling, the only thing that works is if I set a flag inside my controller's submit if the form is invalid to set the error class. I've looked at similar problems here, but none of them helped, so please do not simply dismiss this as a potential duplicate. Everything else has been a fail.
In the example mark up below I have reduced my form down to just one element. Here is what I have observed:
Using only $error.required does work. The ng-class { 'has-error' :registerForm.firstName.$error.required} does outline the text box with the bootstrap has-ertror class, but this is on form load, which I do not want.
The <p> element with the error message will exhibit the same behavior, so I know that the message exists and is not malfored. It will also display if I only use $error.required. But as soon as I add && registerForm.$submitted ( or $isdirty or !notpristine ) the message will not display on form submit. There are no errors (have developers tools open in chrome) and will post to the web API with no problem and return ok 200 or 400 if I send bad params.
I can write validation code inside my controller, checking if the field has a value and setting a flag on $scope such as $scope.firstNameIsRequired and that will work fine setting ng-show="$scope.firstNameIsRequired", but that will remove testability.
So the problem definitely has to be with how I am adding this in the markup. But after a weekend spent googling I am at my wits end. The only other thing different is that I am using a span on a click element to submit the form instead of an input = submit, but the registerForm.$valid function is setting the correct value. Do I somehow need to trigger the form validation in that ng-click directive?
I am using angular.js v 1.4.8.
I do have angular ui which has it's own validate, but that shouldn't interfere with the basic validation.
Here is the simplified markup:
<form name="registerForm" class="form-group form-group-sm"
ng-controller="userAccountController" novalidate>
<div class="form-group"
ng-class="{ 'has-error' : registerForm.firstName.$error.required }">
<div><label>First Name</label> </div>
<input type="text" class="form-control" id="firstName" name="firstName" value=""
ng-model="firstName" placeholder="First Name" maxlength="100" required=""/>
<p ng-show="registerForm.firstName.$error.required && registerForm.$submitted"
class="alert alert-danger">First Name is required</p>
</div>
<div>
<span class="btn btn-default"
ng-click="submit(registerForm.$valid)">Register</span>
</div>
My controller code is
angular.module( "Application" ).controller( "userAccountController", [
"$scope", "userAccountService", function ( $scope, userAccountService)
{
$scope.hasErrors = false;
$scope.errorMessages = "";
$scope.emailExists = true;
$scope.clearErrors = function (){
$scope.hasErrors = false;
}
$scope.onSuccess = function ( response ) {
alert( "succeeded" );
}
$scope.submit = function (isValid) {
if ($scope.registerForm.$invalid)
return;
alert("isvalid");
$scope.clearErrors();
var userProfile = $scope.createUser();
userAccountService.registerUser(userProfile, $scope.onSuccess, $scope.onError);
}
$scope.createUser = function () {
return {
FirstName: $scope.firstName, LastName: $scope.lastName, Email: $scope.email,
Password: $scope.password, SendAlerts: $scope.sendAlerts
};
};
}
]);
Any help will be appreciated. I probably just need a second set of eyes here because I have been dealing with this on and off since late Friday.
in angular you want use the element.$valid to check wheter an model is valid or not - and you use element.$error.{type} to check for a specific validation error.
Keep in mind that the form.$submitted will only be set if the form is actually submitted - and if it has validationerrors it will not be submitted (and thus that flag is still false)
If you want to show errors only on submit you could use a button with type="submit" and bind to ng-click event - and use that to set a flag that the form has been validated. And handling the submit if the form is valid.
A short example with 2 textboxes, having required and minlength validation:
angular.module("myApp", [])
.controller("myFormController", function($scope) {
$scope.isValidated = false;
$scope.submit = function(myForm) {
$scope.isValidated = true;
if(myForm.$valid) {
console.log("SUCCESS!!");
}
};
});
.form-group {
margin: 10px;
padding: 10px;
}
.form-group.has-error {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="myApp" ng-controller="myFormController">
<form name="myForm">
<div class="form-group" ng-class="{'has-error': myForm.name.$invalid && isValidated}">
<span>Name:</span>
<input type="text" name="name" minlength="5" ng-model="name" required />
<span ng-if="myForm.name.$error.required && isValidated">Name is required</span>
<span ng-if="myForm.name.$error.minlength && isValidated">Length must be atleast 5 characters</span>
</div>
<div class="form-group" ng-class="{'has-error': myForm.email.$invalid && isValidated}">
<span>Email:</span>
<input type="text" name="email" minlength="5" ng-model="email" required />
<span ng-if="myForm.email.$error.required && isValidated">Email is required</span>
<span ng-if="myForm.email.$error.minlength && isValidated">Length must be atleast 5 characters</span>
</div>
<button type="submit" ng-click="submit(myForm)">Submit</button>
</form>
</div>

AngularJS ng-include on ng-click

I would like to find a way to insert HTML (which is optimalized for the controller) into alert div. However I couldn't find a way to do it...
<script type="text/ng-include" id="login.html">
<form data-select="exeption" class="loginBox shadowed" onclick="event.stopPropagation();" novalidate name="login">
<h2>Login alert</h2>
<!--inputs and such, they need to be controlled by the controller-->
</form>
</script>
<script type="text/ng-include" id="bug.html">
<form data-select="exeption" class="bugBox shadowed" onclick="event.stopPropagation();" novalidate name="report">
<h2>Bug report</h2>
<!--inputs and such, they need to be controlled by the controller-->
</form>
</script>
This two templates should be evoked by the JS itself or by user. Those templates should get into this div, but I can't use innerHTML since in templates are some ng-models and such things...
<div id="alert" data-ng-click="empty()" data-ng-controller="alert" role="navigation"></div>
Usually what I do is use ng-if / ng-show .
I'm not sure I understood your request correctly, so I'll write a little example; let's say you have a simple login form:
<form>
<label>
username:
<input name="username" type="text" ng-model="username"/>
</label>
<label>
password:
<input name="password" type="password" ng-model="password"/>
</label>
<button type="submit" ng-click="login()">login</button>
<div class="message" ng-if="message">
</div>
</form>
Inside the controller:
$scope.username = '';
$scope.password = '';
$scope.message = '';
$scope.login = function() {
// login example function with ajax request and success/error promises
myLogin($scope.username, $scope.password)
.success(function() {
$scope.message = 'Logged in!';
})
.error(function(errorMessage) {
$scope.message = errorMessage;
})
}
This way your div is empty when $scope.message is empty and you can show it automatically just giving $scope.message a value.
If you need to have an ng-include, simplest thing you could do is to use it inside a div that you show when you need it:
<div ng-if="showMessage">
<div ng-include="template.html"/>
</div>
UPDATE: following my last example, if you wanted to include a different type of message for every situation, you could use multiple ngIf, including different template; example:
<div ng-if="showMessage">
<div ng-if="message.type == 'alert'" ng-include="'alert.html'"/>
<div ng-if="message.type == 'info'" ng-include="'info.html'"/>
<div ng-if="message.type == 'warning'" ng-include="'warning.html'"/>
<div ng-if="message.type == 'error'" ng-include="'error.html'"/>
</div>
This way you can also do an ngInclude for a login form, or another kind of popup.
UPDATE 2: same last example, but with another solution:
<div ng-if="showMessage">
<div ng-include="templatePath"/>
</div>
then you can give in the controller the whole path to the partial:
$scope.templatePath = 'alert.html';

Categories