My custom directive looks like
<cities-directive name="cities" ng-model="obj.cities" required></cities-directive>
The required directive does not work. Initially obj.cities is an empty array. How do I make it compulsory for the user to select at least one city so that obj.cities is not an empty array? Basically this directive is inside a ng-form and I dont want the form to be submitted if the array is still empty.
According to this , you can only use required on 3 types oh html markup :
TextArea
Input
Select
For what you are trying to do, there are some basic solution :
If your custom directive template consists in an input, then you can try to modify your directive so you can use it as an attribute or a class and not as an element. (See A, E and C restrictions). Then apply your directive to a select or input markup.
You can simply use ngDisabled on the button of your form submit to prevent the user to send the form if obj.cities is empty.
<form>
<button ng-disabled="obj.cities.isEmpty()"> Submit </button>
</form>
Related
How can I check for any field changes in a form? I would like to only enable a Save button if the underlying object has changed. Currently, I'm adding a ng-change="vm.formChanged()" attribute to every single field on the form. I would much rather do this once at the form level and not decorate every single field.
My method looks something like this:
formChanged () {
vm.hasChanges = (JSON.stringify(vm.item) != JSON.stringify(vm.original));
}
... and I'm binding the Save button to ng-disabled="!vm.hasChanges".
Assuming you have given a name to your form you could do something like this:
<form name="myForm">
<input type="text" ng-model="form.name">
<input type="text" ng-model="form.age">
<button ng-disabled="myForm.$pristine">Submit</button>
</form>
This will just disable the button as long as the form is pristine. Once the model has changed it will enable the submit button. However, note, if you undo your change to a field, the button will still be enabled since angular assumes the form is no longer pristine.
Here is a link to a working example: http://plnkr.co/edit/RYJIrZ3m4b8jmd0oVIuh?p=preview
You can use "yourForm.$pristine" to check if form has been monified
I'm trying to build widgets directives that play well with forms
The complete example is available at http://jsfiddle.net/jy81bchd/4/
The main idea is:
Write your own form, put widget in it
<form name="otherForm" novalidate ng-init="model = {name: 'test'}" novalidate>
<swif-widget-text name="name" required="required" input-model="model.name">
<span translate>Name</span>
</swif-widget-text>
</form>
The widget directive copy all attributes to the input and transculde the contennt in the the label.
My differents problems are:
1) I can't update the formController of the main form, it doesn't find the different inputs throw directives. The best should be to use formcontrolller.addControl but I don't have succeed with it
2) To work around 1 I have tried to make each widget a different form. This is working execpt formcontroller doesn t update after link has been called (attributed copied to input doesn't affect the controller).
In the fiddle I copied required attribute to the input but if you empty the field it's still valid according to the formcontroller.
I have added name="input" also because if I copy name attribute to the input the form controller doesn't find any input.
Conclusion:
From what I understand formcontroller is initialized and loaded before the link is called.
How could I change that ?
There are several posts about how to create your own form component that plays nicely with the form and the controller that is attached to that.
For instance: http://blog.revolunet.com/blog/2013/11/28/create-resusable-angularjs-input-component/
Examining your fiddle I have a few things you need to look at:
1) add a name and a controller to the form element in order to work with all form elements that live inside of it. Via the $scope that is injected in that controller you can handle the form elements (also add meaningfull names to your form elements).
2) And your custom component:
- should use ng-model instead of input-model.
- should require 'ngModel' in the Directive definition
- in the link phase you get a reference to the ngModelController, and check the link above to see how you should interact with that to achieve a two way binding like behaviour. (using $viewValue, $render and $setViewValue)
I'm trying to implement a multilingual text input field with a little dropdown button to the left for selecting the language. For instance, when the dropdown menu shows 'de' the text field should be bound to model.multilingualData['de'].someField and so on.
My first approach was to set ngModel to model.multilingualData[selectedLanguage].someField. But when the user selects a different language without filling in the field correctly, no error is set on the form, because the model now points to a different object.
My next idea was to create an entire element directive without ngModel, but then I wouldn't be able to do other validations like ngMaxLength.
I couldn't find anything helpful on the web either. Any idea on how to implement this properly?
EDIT
Here's a little fiddle that illustrates the problem: http://jsfiddle.net/FZ2kg/
Not only that the form appears valid when you switch languages, the previous field value is also deleted, because the model is set to null when the field becomes invalid.
would be nice if you use this awesome external directive for multilanguage!
https://angular-translate.github.io/
I hope it helps
If you need to have form validation for all language variations and you're loading all languages at once in your model, can't you just create an input per language in the form and hide all but the currently selected language?
Here's a fiddle: http://jsfiddle.net/jvl70/w3rstmwd/5/
<form name="myForm">
<div ng-repeat="(lang, value) in model.multilingualData"
ng-show="lang==stuff.currentLanguage">
<ng-form name="innerForm">
<div ng-class="{ 'has-error': innerForm.anything.$invalid }">
<input type="text" name="anything" ng-model="value.someField" ng-maxlength="6"/>
</div>
</ng-form>
</div>
</form>
(At first I tried to use dynamic names for each input but found that the individual field $invalid wasn't available for dynamically named inputs. See this post to get around it: Dynamic validation and name in a form with AngularJS.
As an alternative to ng-form, you could use dynamic names for each input and try one of the custom directives on the link.)
I guess if there were many possible languages, this approach might get slower but it's ok for a few languages.
From 1st view seems like data-ng-click can pass some data as argument to method should be invoked during pressing on button.
But I don't see the difference.
I have followed snippets of code:
HTML
<input
type="button"
value="Fess"
ng-click="toggle(2)">
OR
<input
type="button"
value="Fess"
data-ng-click="toggle(2)">
JS
$scope.toggle = function (valueS) {
alert(valueS);
}
Both work.
Thanks,
They are the same thing. You can use data-ng-click to make a valid html.
From the angular docs on directives:
Directives have camel cased names such as ngBind. The directive can be
invoked by translating the camel case name into snake case with these
special characters :, -, or _. Optionally the directive can be
prefixed with x-, or data- to make it HTML validator compliant. Here
is a list of some of the possible directive names: ng:bind, ng-bind,
ng_bind, x-ng-bind and data-ng-bind.
Leaving them out is totally fine for practical purposes. It's just that if you run it through an html validator service, it will not pass as complliant.
HTML5 has an ability to embed custom data attributes on all HTML elements
These new custom data attributes consist of two parts:
Attribute Name
The data attribute name must be at least one character long and must be prefixed with 'data-'. It should not contain any uppercase letters.
Attribute Value
The attribute value can be any string.
<li data-spacing="30cm" data-sowing-time="February to March">Celery</li>
source : http://html5doctor.com/html5-custom-data-attributes/
Found a difference while using with and without Form.
When my element is in a Form they act the same.
When I use data-ng-click on an element not within a form, Click event is not happening.
Normally, with a form and input fields, the form controller is published into the related scope under the form name attribute. And, the NgModelController is published under the input name attribute.
So for an input field with an ngModel directive, the NgModelController for the input field can be retrieved like $scope.myFormName.myInputFieldName
The question is how to do the same thing (get the NgModelController) for input fields inside the ngRepeat directive?
I would like to name the input fields using $index as part of the name so each template instance is uniquely named. This renders OK, so
<input name="foo_{{$index}}" ...
renders the instance with $index == 3 to
<input name="foo_3" ...
But trying to get the ngModelController via the published names does not work (it's undefined), e.g.:
$scope.myFormName.foo_3
A plunker showing this is here: http://plnkr.co/edit/jYDhZfgC3Ud0fXUuP7To?p=preview
It shows successfully getting the ngModelController for a 'plain' input element and calling $setValidity, and also shows failing to get the ngModelController for an input element inside an ngRepeat directive.
Copied the relevant section of code from the plunker below:
<div ng-repeat="element in elements">
<div ng-class="{error: form['foo_{{$index}}'].$invalid}">
<input name="foo_{{$index}}" ng-model="element.a" type="number">
<span ng-show="form['foo_{{$index}}'].$error.bar">ngRepeat bar invalid</span>
</div>
</div>
{{form.foo_0.$setValidity('bar', false)}}
#Flek is correct that the new child scopes that ng-repeat creates are the root of the problem here. Since browsers do not allow nesting of <form> elements, ngForm must be used when nesting forms, or when you want to do form validation inside ngRepeat.
See Pawel's answer on the google group thread, which shows how to use ng-form to create inner forms, and/or #blesh's SO answer.
If i understand your question correctly, you are trying to have access to the form elements created inside the ng-repeat.
Please have a look at this fiddle http://jsfiddle.net/EF5Jp/. Inside the button click handler you will have the access to the element with id myForm.foo_2. You can notice that the element is retrieved by myForm.foo_2 and not $scope.myForm.foo_2. Second thing is, changing the value using its scope and not using its value property like angular.element(element).scope().foo = 6;.