I am able to get the form-control class from Bootstrap to behave well within a single HTML file. But when the form-control is defined from within a directive, the flags like $dirty are not being recognized. The class ng-dirty does appear.
HTML using directive:
<form class="form-horizontal" role="form" name="formExpense">
<div frm-item ng-repeat="f in formdata2"></div>
</form>
Directive:
app.directive('frmItem', function() {
return {
restrict: 'A',
templateUrl: 'form.html'
};
});
Template:
<div class="form-group" ng-class="{'has-error':formExpense.{{f.name}}.$dirty}">
<div class="col-md-6 text-right">
<label for="{{f.name}}-entry">{{f.name}}</label>
</div>
<div class="col-md-6">
<input type="text" name="{{f.name}}" ng-model="f.amount"
class="form-control" placeholder="per month">
</div>
</div>
$scope:
$scope.formdata2 = [{'name': 'housing'},{'name': 'medical'}];
Plunk: http://plnkr.co/JcanBWWTphGdL18v6NxZ
Related
This is my code :
Template :
<div ng-repeat="framework in frameworks" id="{{framework.id}}"
role="tabpanel" class="tab-pane show active" >
<div class="progress" >
<div ng-click="display_framework_formulaire(framework)"
class="progress-bar" role="progressbar"
style="width: {{framework.level}}%"
aria-valuenow="{{framework.level}}"
aria-valuemin="0" aria-valuemax="100">
<div data-toggle="tooltip" data-placement="top"
data-title="{{framework.version}}">
</div>
{{framework.nom}}
</div>
</div>
</div>
This is the function in my controller :
$scope.display_framework_formulaire = function(framework)
{
$scope.frameworkCourant = framework;
$scope.vueCourante = 'VUE_FORMULAIRE_FRAMEWORK'
}
This is the directive in template:
<formulaire-framework ng-show="vueCourante == 'VUE_FORMULAIRE_FRAMEWORK'"
categories="categories" framework="frameworkCourant" >
</formulaire-framework>
And the directive :
app.directive("formulaireFramework", function() {
return {
restrict: "E",
templateUrl: 'formulaireFramework.html',
scope: {
framework : '=framework',
categories : '=categories'
},
}
})
So it's working after loading homepage.
But when i do :
restfulService.getFrameworksByCategorieValue(categorie_value)
.then(function(frameworks){
$scope.frameworks = [];
angular.forEach(frameworks, function(framework, key) {
$scope.frameworks.push(framework);
});
});
Which update the list of frameworks, when i click on a framework, the value of element of formulare is this of last action and not the value of the framework current.
PS : my form :
<form name="frameworkForm" id="frameworkForm" method="POST" class="spacer"
ng-submit="submit()" ng-controller="frameworkFormulaireController" >
<div class="input-group">
<select ng-model="framework.categorie.id">
<option ng-repeat="categorie in categories"
ng-value="categorie.id"
ng-selected="categorie.id == framework.categorie.id" >
{{categorie.label}}
</option>
</select>
</div>
<div class="input-group" >
<input type="text" class="form-control" ng-value="id"
ng-model="framework.id">
</div>
<div class="input-group">
<span class="input-group-addon">Nom</span>
<input type="text" class="form-control" ng-value="nom"
ng-model="framework.nom">
</div>
<div class="input-group">
<span class="input-group-addon">Version</span>
<input type="text" class="form-control" ng-value="version"
ng-model="framework.version">
</div>
<div class="input-group">
<span class="input-group-addon">Niveau</span>
<input type="text" class="form-control" ng-value="level"
ng-model="framework.level">
</div>
<input type="submit" class="btn btn-success pull-right" >
</form>
Remove the ng-controller directive from the form:
<form name="frameworkForm" id="frameworkForm" method="POST" class="spacer"
ng-submit="submit()" ̶n̶g̶-̶c̶o̶n̶t̶r̶o̶l̶l̶e̶r̶=̶"̶f̶r̶a̶m̶e̶w̶o̶r̶k̶F̶o̶r̶m̶u̶l̶a̶i̶r̶e̶C̶o̶n̶t̶r̶o̶l̶l̶e̶r̶"̶ >
<!-- input controls -->
<!-- input controls -->
<!-- input controls -->
<!-- input controls -->
</form>
Add the controller to the directive:
app.directive("formulaireFramework", function() {
return {
restrict: "E",
templateUrl: 'formulaireFramework.html',
controller: 'frameworkFormulaireController',
scope: {
framework : '=framework',
categories : '=categories'
},
}
})
The ng-controller directive adds a new child scope which is unneccessary and can have prototypal inheritance variable hiding problems.
For more information, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?.
I am using custom angular directive for showing validation. Directive code is as below
angularFormsApp.directive('showErrors',['$timeout', function ($timeout) {
return {
restrict: 'A',
require: '^form',
link: function (scope, el, attrs, formCtrl) {
// find the text box element, which has the 'name' attribute
var inputEl = el[0].querySelector("[name]");
// convert the native text box element to an angular element
var inputNgEl = angular.element(inputEl);
// get the name on the text box so we know the property to check
// on the form controller
var inputName = inputNgEl.attr('name');
var helpText = angular.element(el[0].querySelector(".help-block"));
// only apply the has-error class after the user leaves the text box
inputNgEl.bind('blur', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
helpText.toggleClass('hide', formCtrl[inputName].$valid);
});
scope.$on('show-errors-event', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
});
scope.$on('hide-errors-event', function () {
$timeout(function () {
el.removeClass('has-error');
}, 0, false);
});
}
}
}]);
and Html is as below
<div class="container" id="login-form">
<img src="assets/img/logo-big.png">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Login Form</h2>
</div>
<div class="panel-body">
<form name="loginForm" class="form-horizontal" novalidate>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-user"></i>
</span>
<input type="text" class="form-control" placeholder="Username" autocomplete="Off" ng-required="true" name="username" autofocus ng-model="loginUser.username">
</div>
<span class="help-block" ng-if="loginForm.username.$error.required">Username is required</span>
</div>
</div>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12" >
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-key"></i>
</span>
<input type="password" class="form-control" placeholder="Password"
name="password"
ng-model="loginUser.password" autocomplete="Off"
ng-required="true">
</div>
<span class="help-block" ng-if="loginForm.password.$error.required">Password is required</span>
</div>
</div>
<div class="form-group mb-n">
<div class="col-xs-12">
Forgot password?
<div class="checkbox-inline icheck pull-right p-n">
<label for="">
<input type="checkbox"></input>
Remember me
</label>
</div>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<div class="clearfix">
Register
Login
</div>
</div>
</div>
</div>
</div>
</div>
Controller code :
var loginController = function ($scope, $window, $routeParams, $uibModal, $location, $filter, $rootScope, DataService, SharedProperties) {
$rootScope.bodylayout = 'focused-form animated-content';
$scope.loginUser = {
username: "",
password:""
}
$scope.load = function () {
//getAppointmentInfo();
};
$scope.SubmitLoginForm = function () {
$scope.$broadcast('show-errors-event');
if ($scope.loginForm.$invalid)
return;
}
}
angularFormsApp.controller("loginController", ["$scope", "$window", "$routeParams", "$uibModal", "$location", "$filter", "$rootScope", "DataService", "SharedProperties", loginController]);
Now When I open form below input control validation span is displaying by default . When I click on Login button then its showing in red and working fine.
problem is it shouldn't show by default when Page is opend.. Please see image below
Instead of this
loginForm.password.$error.required
try this
(loginForm.$submitted || loginForm.username.$dirty) && loginForm.password.$error.required
Take a look at the ng-messages directive. Its fairly elegant. Example:
<form name="myForm">
<input type="text" ng-model="field" name="myField" required minlength="5" />
<div ng-messages="myForm.myField.$error">
<div ng-message="required">You did not enter a field</div>
<div ng-message="minlength">The value entered is too short</div>
</div>
</form>
You can then combine it with any form validation. Just place the error messages from the validators onto the elements $error object and they are automatically rendered in your UI.
I ended up here as part of my search for an issue. In my case I was using a directive with a changing minimum value like this:
ngOnChanges(changes: SimpleChanges) {
if (changes.minDate && this.control) {
this.control.updateValueAndValidity({ onlySelf: true });
}
}
This means that the form will not be updated, I removed onlySelf and it worked correctly.
this.control.updateValueAndValidity();
Just leaving this as a breadcrumb in case someone else does something similar.
I'm a total beginner in Angular, so maybe I am thinking about it totally wrong.
What I'm trying to do is create a directive that wraps an input in some boilerplate html. It should bind the input's ng-model to the parent scope (the myForm controller's scope) but should have access to the validation state of the input.
Here's my setup:
parent_form.html
<form name="myForm">
<div fieldContainer label="'Field 1'" model="'field1'">
<input type="text" ng-model="field1" required/>
</div>
<div fieldContainer label="'Field 2'" model="'field2'">
<input type="text" ng-model="field2" required/>
</div>
</form>
field_container.html
<div class="row">
<div class="col-md-5">{{label}}</div>
<div class="col-md-5" ng-transclude></div>
<div class="col-md-2" ng-show="valid">REQUIRED!</div>
</div>
parent_form.js
angular.module('myApp')
.controller('myForm', function ($scope) {
$scope.field1 = '';
$scope.field2 = '';
})
.directive('fieldContainer', function () {
return {
restrict: 'A',
templateUrl: 'field_container.html',
transclude: true,
scope: {
label: '=label',
model : '=model'
}
}
});
I got it working by:
Adding a name to the field (so that Angular's Form validation takes over)
Setting ng-show on the validation message to be: $parent.myForm[model].$valid
So apparently the transcluded input still uses the parent (myForm) scope and the directive has access to the parent's scope via scope.$parent.
Not sure if this is the cleanest way to do it...
Final code looks like:
parent_form.html
<form name="myForm">
<div fieldContainer label="'Field 1'" model="'field1'">
<input type="text" name="field1" ng-model="field1" required/>
</div>
<div fieldContainer label="'Field 2'" model="'field2'">
<input type="text" name="field2" ng-model="field2" required/>
</div>
</form>
field_container.html
<div class="row">
<div class="col-md-5">{{label}}</div>
<div class="col-md-5" ng-transclude></div>
<div class="col-md-2" ng-show="$parent.myForm[model].$valid">REQUIRED!</div>
</div>
I'm trying to apply select2 on a select element within a modal.
The modal is defined as a script ng-template. This works fine if it's not a modal (or a template).
<script type="text/javascript">
$(document).ready(function ($) {
$("#typeDescription").select2({
placeholder: 'Select a type...',
allowClear: true
});
});
</script>
However I cannot include the above code within
<script type="text/ng-template" id="myModal">
</script>
So the thing is I want to apply select2 on my element on the modal. How can I do that? How can I access the modal element by id and apply select2 on it?
EDIT:
I made some changes:
On the controller I made a function:
......
$scope.select = function() {
$(document).ready(function ($) {
$("#typeDescription").select2({
placeholder: 'Select a type...',
allowClear: true
});
});
};
and then within my template:
at the select filed (see bellow) I did like this: data-ng-init="select()"
and actually works, it applies the select2 to my element.
Is this a proper approach? Can I make use of ng-init for this case?
<script type="text/ng-template" id="myModal">
<div class="modal-header">
<button type="button" class="close" ng-click="currentModal.close();" aria-hidden="true">×</button>
<h4 class="modal-title">Title</h4>
</div>
<div class="modal-body">
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label" for="field-1">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" data-ng-model="newType.Name" id="field-1" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="field-5">Description</label>
<div class="col-sm-10">
<textarea class="form-control" data-ng-model="newType.Description" cols="5" id="field-5" placeholder="Description"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="field-5">Select Type</label>
<div class="col-sm-10">
<select class="form-control" id="typeDescription" data-ng-model="newType.Type" data-ng-init="select()">
<option data-ng-repeat="item in allTypes.Types" value="{{item.Value}}">{{item.Text}}</option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-gray btn-single" data-ng-click="currentModal.close();">Cancel</button>
<button type="button" class="btn btn-info btn-single" data-ng-click="createType(); currentModal.dismiss();">Save</button>
</div>
</script>
I would recommend that you create a directive wrapping the select2 plugin:
var lib = angular.module('lib');
lib.directive('mySelect', [function() {
var link = function (scope, element, attrs) {
element.select2({
placeholder: attrs.placeholder,
allowClear: attrs.allowClear
});
}
return {
restrict: 'A',
link: link
};
}]);
use it like this:
<select data-my-select placeholder="'Select a type...'" allowClear="true"></select>
This will initialize the select2 when the select control is rendered.
I have a segment of code needs to be reuse a lot, there for I want to just create a directive for it.
<div class="btn-group">
<div class="input-group">
<div class="has-feedback">
<input type="text" class="form-control" placeholder="BLAH BLAH" ng-model="model">
<span class="times form-control-feedback" ng-click="model=''" ng-show="model.length > 0"></span>
</div>
</div>
</div>
I want to use this code as template in directive.
Create a directive used as follow:
<div search-Field ng-model="model" placeholder="STRING"></div>
to replace to old html, ng-model and placeholder will be as variables.
angular.module('searchField', [])
.directive('searchField', [function () {
return {
scope: {
placeholder: '#',
ngModel: '='
},
templateUrl: 'Partials/_SearchInputGroup.html'
}
}]);
Is it the way of doing it?
That looks fine.
Here is a sample for you -http://plnkr.co/edit/LCWHRj6xc9bxwrgpaAb4
corrected few typos and binded placeholder and ngModel data in the directive.
Template:
<div class="btn-group">
<div class="input-group">
<div class="has-feedback">
<input type="text" class="form-control" placeholder="{{placeholder}}" ng-model="ngModel">
<span class="times form-control-feedback" ng-click="model=''" ng-show="ngModel.length > 0">Show</span>
</div>
</div>
</div>