Conditional HTML5 attributes in AngularJS? - angularjs

<input ng-model="example" required>
Is it possible to include or exclude the attribute "required" based on a condition?

you can use
<input type="text" ng-required="isRequired"/>
where in your controller:
$scope.isRequired = true;
Just set your scope variable to whatever condition you want!

Actually I posted "required" just as an example. In my particular case
it's a custom attribute and the presence of it whether the value of
true or false affects the functionality. So I need to not include the
attribute depending on the condition.
if this is in reference to empty HTML5 attributes and removing the attribute itself to avoid a boolean true condition then:
Example from MDN docs element.removeAttribute() :
// <div id="div1" align="left" width="200px">
document.getElementById("div1").removeAttribute("align");
// now: <div id="div1" width="200px">
Then according to AngularJS docs on angular.element and this external blog post you can:
remove an attribute with: angular.element(DOMelement).removeAttr(attribute)
read an attribute with angular.element(DOMelement).attr(attribute)
set an attribute with angular.element(DOMelement).attr(attribute, value)
Note: all element references in Angular are always wrapped with jQuery
or jqLite; they are never raw DOM references.
hope this helps - GL!
EDIT1: Here's an SO discussion about DOM manipulation and Angularjs here's another
EDIT2: Here's an external tutorial on how to create an AngularJS Directive for DOM manipulations (including Unit testing)

Related

How to use ng-model as element rather than attribute?

I want to use ng-model directive as element rather than as attribute inside tag,is there any way to do it?
well I've already designed my webpage in html and javascript and I want to include it in angularJS using "ng-include". So rather than adding attribute like,
<input type="checkbox" id="checkbox" name='rejectedPartsConfirmtodothis' ng-model="reject">
I want to put it in the format like, (as said in angulaJS documentation )
<ng-model>
<input --->
</ng-model>
but this is not working, any idea how can I make it work?
Quoting the content of the page
Usage
as element: (This directive can be used as custom element, but be aware of IE restrictions).
<ng-model>
...
</ng-model>
according to v1.5 official documentation : https://docs.angularjs.org/api/ng/directive/ngModel
Usage
as element: (This directive can be used as custom element, but be aware of IE restrictions).
<ng-model>
...
</ng-model>
I dont really think there would be a use case where you would really need to do this...instead try some alternative but use ng-model as an attribute as ng-model is a pre-defined directive given by angularjs...
You can build a new directive but you cannot modify ng-model to work as an element.

Require fields from a directive field type

Reference this example: http://jsbin.com/cenugiziju/edit?html,js,output
I have created a directive: example-directive
This directive is made up of a templateUrl which has a label and an input within this html file. This field is marked as required within vm.formFields.
If you take a peek down within the Form section, you will notice that $valid is already set to true even though the required directive is not populated. I would have expected this to be false.
Is there a way to make Formly require fields that are brought in from a custom directive which has fields on it?
ok
sorry about the mixup and delay.
I have created the answer you were looking for.
because you are entering a directive you actually need to send the options to that directive with the values you need...
this is the working example... this means though you will need to handle all the validations and so on yourself since you are not generating the element via FormalyJS but in your own directive.(make sure there is no other way to do it...)
this is the corrected code with required/ maxlength /minlength:
jsbin
what I actually did was pass the options for the Formly to my directive and add the validations to it
app.directive('exampleDirective', function() {
return {
templateUrl: 'example-directive.html',
scope:{
options:'=options',
ngModel:'=ngModel'
},
link:function(scope, element, attrs){
scope.isRequired = scope.options.templateOptions.required;
scope.minValue = scope.options.templateOptions.min;
scope.maxValue = scope.options.templateOptions.max;
}
};
});
<script type="text/ng-template" id="example-directive.html">
<div class="form-group">
<label for="{{::id}}">{{options.templateOptions.label}}</label>
<input id="{{::id}}" name="{{::id}}" class="form-control" ng-model="ngModel" ng-required="isRequired" ng-minLength="{{minValue}} ng-maxLength={{maxValue}}"/>
</div>
</script>
this is the addition to the template in the vm.formFields
template: ''
so now when you want to add a field you will need to pass the data to the directive and in the directive add the corresponding code...
I am not hugely familiar with Formly, but this is the solution that I can give you
NOTE:
I pass the option item to the directive because this is how FormalyJS constructs it.... you can always use your own... but since it renders after the formly directive, figured it would be easier
EDIT
here is an updated JSBIN
you can see that I had to add to the directive the ngModel... you can also do it by require and then use it, I prefer to do it like this... but you have to pass it to the div defining the directive...
checkout the updated code

When to use ng-attr?

It seems like using direct attributes and the ng-attr-* directive do the same thing. For example, the following render equivalently:
<div ng-attr-id="{{ 'object-' + value }}">ID</div>
<div id="{{ 'object-' + value }}">ID</div>
When should I use ng-attr-* and when should I use the direct HTML attribute?
ng-attr is used for add or not the attribute in context. If the expression {{undefined || null}}, the attribute is not added otherwise if has a value then attribute is added with the value {{ value }}.
The most common cases is in interpolation.
Related:
Conditionally adding data-attribute in Angular directive template
You use them for custom html data attributes - like if you wanted an attribute of let's say myData you would do
<div ng-attr-myData="{{ 'object-' + value }}">ID</div>
There are only a few situations where ng-attr-[attribute]="{{angular stuff}}" is different from just [attribute]="{{angular stuff}}". Certain elements within certain browsers can be broken if ng-attr is not used. Angular's documentation lists a few examples:
size in <select> elements (see issue 1619)
placeholder in <textarea> in Internet Explorer 10/11 (see issue 5025)
type in <button> in Internet Explorer 11 (see issue 14117)
value in <progress> in Internet Explorer = 11 (see issue 7218)
Source: https://docs.angularjs.org/guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes
ng-attr can be used to dynamically assign value to an attribute of any html element.
One case, where I used it was to associate a label to a form control with dynamic id.
<label ng-attr-for="{{parameter.name}}">{{ parameter.name }}</label>
<input ng-attr-id="{{parameter.name}}" type="text">
Also, it can be used to assign dynamic value to a custom attribute.
Reference: here

Change value of input placeholder via model?

I'm trying to change the value of the input placeholder from a controller but cant quite figure out how.
input(type='text', ng-model='inputText', side='30', placeholder='enter username')
Is there a way to modify a model's element attributes?
You can bind with a variable in the controller:
<input type="text" ng-model="inputText" placeholder="{{somePlaceholder}}" />
In the controller:
$scope.somePlaceholder = 'abc';
The accepted answer still threw a Javascript error in IE for me (for Angular 1.2 at least). It is a bug but the workaround is to use ngAttr detailed on https://docs.angularjs.org/guide/interpolation
<input type="text" ng-model="inputText" ng-attr-placeholder="{{somePlaceholder}}" />
Issue: https://github.com/angular/angular.js/issues/5025
Since AngularJS does not have directive DOM manipulations as jQuery does, a proper way to modify attributes of one element will be using directive.
Through link function of a directive, you have access to both element and its attributes.
Wrapping you whole input inside one directive, you can still introduce ng-model's methods through controller property.
This method will help to decouple the logic of ngmodel with placeholder from controller.
If there is no logic between them, you can definitely go as Wagner Francisco said.
As Wagner Francisco said, (in JADE)
input(type="text", ng-model="someModel", placeholder="{{someScopeVariable}}")`
And in your controller :
$scope.someScopeVariable = 'somevalue'

Cannot get textarea value in angularjs

Here is my plnkr: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview You have to click on a li element and the form will appear. Enter a random string and hit 'add notice'. Instead of the textarea text you will get undefined.
Markup:
<ul>
<li ng-repeat="ticket in tickets" ng-click="select(ticket)">
{{ ticket.text }}
</li>
</ul>
<div ui-if="selectedTicket != null">
<form ng-submit="createNotice(selectedTicket)">
<textarea ng-model="noticeText"></textarea>
<button type="submit">add notice</button>
</form>
</div>
JS part:
$scope.createNotice = function(ticket){
alert($scope.noticeText);
}
returns 'undefined'. I noticed that this does not work when using ui-if of angular-ui. Any ideas why this does not work? How to fix it?
Your problem lies in the ui-if part. Angular-ui creates a new scope for anything within that directive so in order to access the parent scope, you must do something like this:
<textarea ng-model="$parent.noticeText"></textarea>
Instead of
<textarea ng-model="noticeText"></textarea>
This issue happened to me while not using the ng-if directive on elements surrounding the textarea element. While the solution of Mathew is correct, the reason seems to be another. Searching for that issue points to this post, so I decided to share this.
If you look at the AngularJS documentation here https://docs.angularjs.org/api/ng/directive/textarea , you can see that Angular adds its own directive called <textarea> that "overrides" the default HTML textarea element. This is the new scope that causes the whole mess.
If you have a variable like
$scope.myText = 'Dummy text';
in your controller and bind that to the textarea element like this
<textarea ng-model="myText"></textarea>
AngularJS will look for that variable in the scope of the directive. It is not there and thus he walks down to $parent. The variable is present there and the text is inserted into the textarea. When changing the text in the textarea, Angular does NOT change the parent's variable. Instead it creates a new variable in the directive's scope and thus the original variable is not updated. If you bind the textarea to the parent's variable, as suggested by Mathew, Angular will always bind to the correct variable and the issue is gone.
<textarea ng-model="$parent.myText"></textarea>
Hope this will clear things up for other people coming to this question and and think "WTF, I am not using ng-if or any other directive in my case!" like I did when I first landed here ;)
Update: Use controller-as syntax
Wanted to add this long before but didn't find time to do it. This is the modern style of building controllers and should be used instead of the $parent stuff above. Read on to find out how and why.
Since AngularJS 1.2 there is the ability to reference the controller object directly instead of using the $scope object. This may be achieved by using this syntax in HTML markup:
<div ng-controller="MyController as myc"> [...] </div>
Popular routing modules (i.e. UI Router) provide similar properties for their states. For UI Router you use the following in your state definition:
[...]
controller: "MyController",
controllerAs: "myc",
[...]
This helps us to circumvent the problem with nested or incorrectly addressed scopes. The above example would be constructed this way. First the JavaScript part. Straight forward, you simple do not use the $scope reference to set your text, just use this to attach the property directly to the controller object.
angular.module('myApp').controller('MyController', function () {
this.myText = 'Dummy text';
});
The markup for the textarea with controller-as syntax would look like this:
<textarea ng-model="myc.myText"></textarea>
This is the most efficient way to do things like this today, because it solves the problem with nested scopes making us count how many layers deep we are at a certain point. Using multiple nested directives inside elements with an ng-controller directive could have lead to something like this when using the old way of referencing scopes. And no one really wants to do that all day!
<textarea ng-model="$parent.$parent.$parent.$parent.myText"></textarea>
Bind the textarea to a scope variable's property rather than directly to a scope variable:
controller:
$scope.notice = {text: ""}
template:
<textarea ng-model="notice.text"></textarea>
It is, indeed, ui-if that creates the problem. Angular if directives destroy and recreate portions of the dom tree based on the expression. This is was creates the new scope and not the textarea directive as marandus suggested.
Here's a post on the differences between ngIf and ngShow that describes this well—what is the difference between ng-if and ng-show/ng-hide.

Resources