I am using angular js and the chosen plugin for my dropdowns. I want a validator to show when nothing has been selected in the dropdown. But because chosen replaces the select with some divs and uls, and the select gets hidden, the validation doesn't work. Is there a way I could achieve this with angular? This is my code:
<form class="form-horizontal" role="form" novalidate name="newEmployeeForm">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">User</label>
<div class="col-sm-8">
<select class="form-control" name="user" data-placeholder="Choose a user" ng-model="selectedUser" ng-options="u.fullName for u in users" list="users" chosen required></select>
</div>
<span class="error" data-ng-show="newEmployeeForm.user.$error.required">*</span>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="email" name="email" placeholder="Email" ng-model="employee.email" required>
</div>
<span class="error" data-ng-show="newEmployeeForm.email.$error.required">*</span>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="save()" data-ng-disabled="newEmployeeForm.$invalid">Save changes</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</form>
the directive:
app.directive('chosen', function () {
return {
replace: true,
restrict: 'A',
scope: {
list: "="
},
link: function (scope, element, attr) {
scope.$watch('list', function (newVaue, oldValue) {
if (newVaue == oldValue) {
return;
}
element.chosen();
})
}
}
});
Related
I want to display an error using angularjs, under the "confirm password" input which should say "Passwords don't match".
<form name="settingsForm" ng-submit="vm.login(vm.credentials)" novalidate>
<md-input-container class="md-block" flex-gt-sm="">
<label translate="MY_PROFILE_NEW_PASSWORD"></label>
<input type="password" name="newPassword" id="password"
ng-model="vm.newPassword"
required=""
ng-minlength="8"
md-maxlength="40">
<div ng-messages="settingsForm.newPassword.$error"
role="alert"
multiple="">
<div ng-message="required"
class="my-message"
translate="LOGIN_PASSWORD_INVALID">
</div>
<div ng-message="minlength"
class="my-message"
translate="MIN_8_CHARS">
</div>
</div>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm="">
<label translate="MY_PROFILE_CONFIRM_NEW_PASSWORD"></label>
<input type="password"
name="confirmPassword"
id="confirmPassword"
ng-model="vm.confirmPassword"
required=""
confirm-password="vm.newPassword"
ng-minlength="8"
md-maxlength="40">
<div ng-messages="settingsForm.$error.confirmPassword"
role="alert" multiple="" >
<div ng-message="required"
class="my-message"
translate="LOGIN_PASSWORD_INVALID">
</div>
<div ng-message="minlength"
class="my-message"
translate="MIN_8_CHARS">
</div>
</div>
<div ng-message="required"
class="my-message"
translate="LOGIN_PASSWORD_INVALID">
</div>
<div ng-message="confirm-password"
class="my-message">
Passwords don't match.
</div>
</md-input-container>
<md-button class="md-raised md-primary btn-auth"
type="submit"
ng-disabled="settingsForm.$invalid"
translate="SUBMIT"
ng-click="vm.changePassword(vm)">
</md-button>
I need to make this form display error messages for each particular case.
I haven't found how "confirm-password" attribute should work for validation.
You have to create a Custom Directive. Try this.
<div data-ng-controller="PasswordController as vmPassword">
<form name="passwordForm">
<md-input-container class="md-block" flex-gt-sm>
<label>Password</label>
<input type="password"
name="password"
ng-model="vmPassword.password"
required
/>
<div ng-messages="passwordForm.password.$error" role="alert" class="form-errors first-name-error">
<div ng-message="required">Password is required.</div>
</div>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm>
<label>Confirm Password</label>
<input type="password"
name="confirm_password"
ng-model="vmPassword.confirm_password"
required
compare-to="vmPassword.password"
/>
<div ng-messages="passwordForm.confirm_password.$error" role="alert" class="form-errors first-name-error">
<div ng-message="required">Password is required.</div>
<div ng-message="compareTo">Passwords do not match</div>
</div>
</md-input-container>
</form>
</div>
Custom Directive
(function () {
"use strict";
angular.module('app').directive('compareTo', compareTo);
compareTo.$inject = [];
function compareTo() {
return {
require: "ngModel",
scope: {
compareTolValue: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
return modelValue == scope.compareTolValue;
};
scope.$watch("compareTolValue", function() {
ngModel.$validate();
});
}
};
}
})();
Goodluck .! :)
Demo here - http://embed.plnkr.co/UK4G4Lm5BCNNe5SWoA9r/
I'm trying to create an accordion on button click using AngularJS directive. I have external template for creating accordion. But I couldn't get it working. Here is the code:
Directive:
(function() {
'use strict';
angular.module('accountApp')
.directive('addSubsite', addSubsite);
function addSubsite ($compile, $templateRequest){
var ddo = {
restrict: 'A',
link: function(scope, element) {
element.bind("click", function(e){
$templateRequest("addSubsiteTemplate.html").then(function(html){
var template = angular.element(html);
$element.append(template);
$compile(template)(scope);
$element.find(".add-subsites").append(template);
});
});
}
};
return ddo;
}
})();
index.html
<button add-subsite type="button" class="btn btn-primary pull-right margin10-b"id="aid-addSubSitebtn">Add Sub-Site</button>
<accordion>
<accordion-group>
<div class="accordion-heading header">
<a class="accordion-toggle" id="primary__site__address" data-toggle="collapse" href="#primary__site">
<h4><span class="pull-left"><i class="icon-minus"></i></span>Business Name (Primary Site)</h4></a>
</div>
<div class="form-group">
<label for="exampleInputName2">Name</label>
<input type="text" class="form-control" id="exampleInputName2" placeholder="Jane Doe">
</div>
<div class="form-group">
<label for="exampleInputEmail2">Email</label>
<input type="email" class="form-control" id="exampleInputEmail2" placeholder="jane.doe#example.com">
</div>
<button type="submit" class="btn btn-default">Send invitation</button>
</accordion-group>
</accordion>
Template.html
<accordion>
<accordion-group>
<div class="accordion-heading header">
<a class="accordion-toggle"data-toggle="collapse" href="#subsite__site">
<h4><span class="pull-left"><i class="icon-minus"></i></span>Business Name (SubSite)</h4></a>
</div>
<div class="form-group">
<label for="exampleInputName2">Name</label>
<input type="text" class="form-control" id="exampleInputName2" placeholder="Jane Doe">
</div>
<div class="form-group">
<label for="exampleInputEmail2">Email</label>
<input type="email" class="form-control" id="exampleInputEmail2" placeholder="jane.doe#example.com">
</div>
<button type="submit" class="btn btn-default">Send invitation</button>
</accordion-group>
</accordion>
I changed my approach Here is the sample https://jsfiddle.net/2u7aLg5c/
angular.module('testApp',[])
.controller('TestController', function(){
const vm = this;
vm.inputs=[{}];
vm.myInput = [];
vm.add = function(){
vm.inputs.push({})
}
})
I've created a custom directive to serve as a template to show some information using ng-repeat. I also need to do some manipulation on the array that being looped. My question is how can I remove or add elements to that array, if each element is inside a separate scope inside a stand-alone directive? Without the use of the directive the task is easy:
<div class="well" ng-repeat="dat in data">
<form novalidate>
<div class="form-group">
<label for="name">name:</label>
<input type="text" class="form-control" id="name" ng-model="dat.name" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="balance">balance:</label>
<input type="text" class="form-control" id="balance" ng-model="dat.balance" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="fruit">favorite Fruit:</label>
<input type="text" class="form-control" id="fruit" ng-model="dat.favoriteFruit" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="greeting">greeting:</label>
<input type="text" class="form-control" id="greeting" ng-model="dat.greeting" ng-disabled="enableEdit">
</div>
<button class="btn btn-danger" ng-click="remove($index)">remove</button>
<button class="btn btn-default" ng-click="enableEdit=!enableEdit">edit</button>
<button class="btn btn-success" ng-click="save(dat,$index);enableEdit=!enableEdit" ng-disabled="enableEdit">save</button>
</form>
</div>
After the refactoring to directive, the task is not so obvious:
<div class="well" ng-repeat="dat in data">
<data-directive user="dat" index="{{$index}}" arr="data"></data-directive>
</div>
The directive template looks as follows:
<form novalidate>
<div class="form-group">
<label for="name">name:</label>
<input type="text" class="form-control" id="name" ng-model="user.name" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="balance">balance:</label>
<input type="text" class="form-control" id="balance" ng-model="user.balance" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="fruit">favorite Fruit:</label>
<input type="text" class="form-control" id="fruit" ng-model="user.favoriteFruit" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="greeting">greeting:</label>
<input type="text" class="form-control" id="greeting" ng-model="user.greeting" ng-disabled="enableEdit">
</div>
<button class="btn btn-danger" ng-click="remove(index)">remove</button>
<button class="btn btn-default" ng-click="enableEdit=!enableEdit">edit</button>
<button class="btn btn-success" ng-click="save(user,$index);enableEdit=!enableEdit" ng-disabled="enableEdit">save</button>
</form>
Directive js:
app.directive("data-directive", ["dataService", function (dataService) {
return {
restrict: 'E',
templateUrl:"directives/dataDirectiveTemplate.html",
scope:{
user: "=",
index: "#",
arr: "="
},
controller: function ($scope) {
$scope.enableEdit = true;
$scope.remove = function (index) {
console.log(arr);
dataService.removeItem(arr, parseInt(index));
};
$scope.save = function (item,index) {
dataService.saveItem(item, index, $scope.data);
};
$scope.changes = function () {
console.log($scope.data);
};
}
}
}]);
I managed to pass the $index variable, but how do I pass the whole data array of objects?
Let's first define an owner for data. It can be the controller whose view is using data-directive or dataService.
Now, owner holds data and all responsibility to manipulate it.
If it is dataService, its method can be called from the directive and data is already available with it.
If it is controller it can pass method using & e.g.:
scope: {
user: "=",
index: "#",
arr: "=",
onRemove: "&",
onSave: "&",
onChange: "&",
},
I am trying to submit a simple contact form. The form is inside a bootstrap modal (don't think that makes any difference) but the controller is in a directive.
The html for the form is as followed:
<form name="contactForm" ng-submit="contactForm()" novalidate>
<div class="form-group">
<div class="col-lg-6 col-md-6 col-sm-6">
<input type="text" placeholder="Full name" name="name" ng-minlength="3" max="20"
ng-model="name" id="name" class="form-control">
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<input type="email" ng-minlength="4" placeholder="Email address" name="contactEmail"
ng-model="email" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12">
<input type="text" ng-model="subject" name="subject" ng-minlength="10" id=""
placeholder="Subject" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12">
<textarea class="form-control" ng-model="message" name="message" ng-minlength="10"
placeholder="Your message"></textarea>
</div>
</div>
<div class="modal-footer">
<div class="col-lg-12 col-md-12 col-sm-12">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
</form>
Which i think is all good. The body of my controller looks like this
$rootScope.contactForm = contactForm();
function contactForm() {
console.log('triggered!');
var contactFormVars = {
name: $rootScope.name,
contactEmail: $rootScope.contactEmail,
subject: $rootScope.subject,
message: $rootScope.message
}
// With Promise
Stamplay.Object('contactform')
.save(contactFormVars)
.then(function(res) {
console.log('yes!');
}, function(err) {
console.log('No!');
})
}
return directive;
};
EDIT: Controller now looks like this:
function contactForm($rootScope,$stamplay,$q) {
$rootScope.data = {}
$rootScope.data = {
name: $rootScope.data.name,
contactemail: $rootScope.data.contactemail,
subject: $rootScope.data.subject,
message: $rootScope.data.message
}
Stamplay.Object("contactform")
.save($rootScope.data, function (err, res) {
console.log(res);
console.log(err);
// res is the new car object
});
}
When i click the submit button I get the following error which i've been Googling
Error: v2.contactForm is not a function. (In 'v2.contactForm()', 'v2.contactForm' is an instance of FormController)
fn
Any help with this is appreciated.
EDIT
Ok so now i've moved the js from a directive and placed it in to the main controller. At the moment its not making any difference, only that the error has changed very slightly:
angular.js:12722Error: v4.contactForm is not a function. (In 'v4.contactForm(ensureSafeObject(v5,text))', 'v4.contactForm' is an instance of FormController)
fn
Not sure what the difference between v2 and v4 is.
Any advice to get past this blocker is appreciated.
I have this html form:
<div class="modal-body">
<form name="addAdminForm">
<div class="form-group addPopupLabel">
<div class="container-fluid-full" id="email3">
<input placeholder="Email" type="text" ng-model="model.email" required />
</div>
<div class="container-fluid-full">
<input placeholder="Password (at last 6 characters)" type="password" ng-model="model.password1" id="pw1" name="pw1" required />
</div>
<div class="container-fluid-full">
<input placeholder="Confirm password" type="password" ng-model="model.password2" id="pw2" name="pw2" required password-compare="pw1" />
</div>
<div class="container-fluid-full">
<label>Admin</label>
<input type="radio" class="form-control" name="role" ng-model="model.role" ng-value="userRoles.admin">
</div>
<div class="container-fluid-full">
<label>CS</label>
<input type="radio" class="form-control" name="role" ng-model="model.role" ng-value="userRoles.cs">
</div>
<div>
<span class="errormessage" style="color:red">{{errormessage}}</span>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-disabled="addAdminForm.$invalid" ng-click="createForm.$invalid || ok()">Submit</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
The problem: button stay on disable mode while one of the fields is on focus.
How can i solve it by FormController?
The addAdminForm is scoped within the form. So one option is to move the buttons within the form, or move the form element so that it wraps the buttons. I would prefer this since it is dead simple and most times doable.
If it is not possible for some reason, you can make a directive to export the $invalid flag of a form to a variable of the outer scope. A simple implementation would be:
app.directive('bindValidity', ['$parse', function($parse) {
return {
restrict: 'A',
scope: false,
controller: ['$scope', '$attrs', function($scope, $attrs) {
var assign = $parse($attrs.bindValidity).assign;
if (!angular.isFunction(assign)) {
throw new Error('the expression of bindValidity is not settable: ' + $attrs.bindValidity);
}
this.setFormController = function(formCtrl) {
if (!formCtrl) {
throw new Error('bindValidity requires one of <form> or ng-form');
}
$scope.$watch(
function () {
return formCtrl.$invalid;
},
function (newval) {
assign($scope, newval);
}
);
};
}],
require: ['?form', '?ngForm', 'bindValidity'],
link: function (scope, elem, attrs, ctrls) {
var formCtrl, bindValidity;
formCtrl = ctrls[0] || ctrls[1];
bindValidity = ctrls[2];
bindValidity.setFormController(formCtrl);
}
};
}]);
Use it as:
<div class="modal-body">
<form name="addAdminForm" bind-validity="some.variable">
...
</form>
<div class="modal-footer">
<button ... ng-disabled="some.variable" ng-click="some.variable || ok()">Submit</button>