Dynamic Attributes with AngularJS - angularjs

In some cases I need to apply different attributes to a node based on properties in my model.
For example, in one case I need to add a 'required' tag and in another case not. I've been using ng-if with different branches to accomplish this but the cases are getting out of hand quickly.
<div ng-if="model.required">
<input class="form-control"
type="text"
required
ng-model="model" />
</div>
<div ng-if="!model.required">
// as different options arise,
// i have more forks for each attribute combo
<input class="form-control"
type="text"
ng-model="model" />
</div>
Is there a better way to dynamic apply attributes to nodes?

I have quickly created a directive that allows you specify attributes dynamically.
http://jsfiddle.net/HB7LU/1806/
I'm not sure if it will have the desired effect you are after in this simple form, but it might be a good starting point. You essentially use:
<div dyn-attrs="someModelArray"></div>
And set your model accordingly:
$scope.someModelArray = [
{ attr: 'myattribute', value: '' },
{ attr: 'anotherattribute', value: 'val' }
];

In this case it would be best to make use of ngRequired:
<input class="form-control" type="text" ng-required="model.required" />

Related

How to make Angular Forms ngModel classes inherit from Bootstrap Forms classes

I am using Bootstrap 4 to style my form controls, and want to use the Bootstrap Forms validation styles when Angular's ngModel adds CSS classes to forms, such as ng-valid, ng-invalid, ng-dirty, ng-pending.
For example, if I have the following form
<form novalidate>
<input type="email" class="form-control" ng-model="user.email" required />
</form>
and want to apply Bootstrap's .has-danger class when the control fails data validation with Angular (i.e. when ngModel adds the class .ng-invalid). How do I accomplish this or something to the effect of
input.ng-invalid {
/* inherit from bootstrap's
.form-control-danger */
}
I would use ng-class for applying the bootstrap classes. Bootstrap defines the styling of the classes once applied.
<form name='myForm'>
<input type="email" name='input' class="form-control" ng-model="user.email" ng-class="myForm.input.$valid ? '' : 'has-danger' " required />
//or get fancy with the object argument form of ng-class
... ng-minlength='3' ng-class="{
has-success: myForm.input.$valid,
has-warning: myForm.input.$error.minlength,
has-error: myForm.input.$error.required}"
Checkout: https://docs.angularjs.org/api/ng/directive/form
In Angular2 you can use the same approach as the #Tyler answer but with the new syntax.
<div
class="form-group"
[ngClass]="{ 'has-success': user.valid, 'has-error': user.invalid}"
>
<input
type="text"
class="form-control"
id="usr"
name="usr"
required
#user="ngModel"
[(ngModel)]="model.usr"
>
</div>
You create a new variable named user, line #user="ngModel", which contains the model state for user input. And with [ngClass]="{ 'class-name': bool-expression}" you assign classes when they expressions become true.
Have in mind that you need to put the classes names as strings if they aren't a valid JavaScript identifier (they have an - for example).

Angularjs placeholder not showing when dynamically generate textbox

I am generating a dynamically text boxes using angularjs. I set a array in controller and repeating in view with ng-repeat. Here is controller code :-
this.total_options = [
{text : 'form.options.Option1' , placeholder: 'Enter Option Here'},
{text: 'form.options.Option2', placeholder: 'Enter Option Here' }
];
Now in view i am repeating this options like :-
<li data-ng-repeat="option in mcssController.total_options">
<input required="required" type="text" ng-model="option.text" class="option" placeholder="{{option.placeholder}}" />
</li>
But when page is rendered the textbox showing ng-model property 'form.options.optoin1' instead of placeholder('Enter Option Here'). How can i solve this problem ?
See if you clear out the form, you should be able to see the placeholder!
Try:
<li data-ng-repeat="option in mcssController.total_options">
<input required="required" type="text" ng-init="model=$eval(option.text)" ng-model="model" class="option" placeholder="{{option.placeholder}}" />
</li>
You want ngModel to bind to a model, not a property that represents a string. Since you want to interpret the string as a model, you can use $scope.$eval. It should work if you use $scope.$eval in an ngInit expression, and then use result to bind to ngModel.

Detecting value change in ng-model without using $watch and form for application having large number of models

My application has a lot of models in the page. I want to detect whether user has changed value of any model on click of save. Using $watch on every model puts too much load, so don't want to use this method. Is there any good approach for this?
Small snippet is like below:
<div>
<div class="ttere2">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="specificDays" />
<input class="ggfe1" ng-model="nc2AfterDays" ng-disabled="nc2PenaltyAfter!='specificDays'" type="number" min="1" max="100" step="1" value="1" />days</div>
<div class="admin_wp-line">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="immediately"/> Immediately </div>
<div class="acfv1">model 1</div>
</div>
<div style="margin-top: 20px;"><button ng-click="saveData();">Done</button></div>
............too many inputs go here
</div>
Use .$dirty! Angular will set this on every element that is bound using ng-model, automatically, when it has been changed. It will also set it on the entire form. You can access it in code like this:
if ($scope.myForm.$dirty) {
// Your code here
}
Angular will provide six useful variables on the form, and every ngModel-bound element in your form: $dirty and $pristine, $valid and $invalid, and $touched and $untouched. You can mix and match these to drive a lot of useful behaviors, and they're available both in your controller (using the expression shown above) and your template (directly).

Angularjs dynamic binding for ng-model

Here is the Plunker that describe my problem with dynamic binding in Angularjs.
http://plnkr.co/edit/fGgtOZ5IrJVo9QasQALc?p=preview
Before using Angularjs, I am used to using the input name/value like the following to generate desirable data structure for back end processing
<input type="text" name="computer[details][][purchaseddate]" />
<input type="text" name="computer[details][][warrantyperiod]" />
With Angularjs ng-model, it is possible to bind a complex data structure like
<input type="text" ng-model="computer.parts[0].name" />
However it does not work with dynamic property like the following:
<input type="text" ng-model="computer.details[0].name" />
Angular keeps telling me that I am trying to set property 'name' to undefined 'details[0]', I am aware of that but are there any ways to get the same behavior with previous input's name/value where I can specify dynamic property without having to declare it first?
Thank you,
Binding to attributes that don't exist yet works. You can bind to a.b.c even if $scope.a does not exists. Angular creates the objects and attributes on-the-fly.
<input type="text" ng-model="a.b.c" />
But you are trying to bind to an array element that does not exist yet:
<input type="text" ng-model="a.b[0].c" />
Angular would have instantiate the array and then push an empty object in it and then assign it's name. Apparently this does not work.
I ran into the same situation and tried everything.
This is how I was able to get dynamic values inside 2 deep ng-repeat:
JS:
$scope.newContact = {
name: [],
phone: [],
email: [],
notes: []
};
$scope.saveNewContact = function (idx) {
console.log($scope.newContact.name[idx]);
};
HTML:
<input type="text" ng-model="newContact.name[$index]" />
<input type="text" ng-model="newContact.phone[$index]" />
<input type="text" ng-model="newContact.email[$index]" />
<input type="text" ng-model="newContact.notes[$index]" />
<button ng-click="saveNewContact($index)">Save</button>

How to bind 2 models to one input field in Angular?

Is there anyway that I can bind two model values to one input field?
Suppose I have input field which I want to be the value of two variables in the scope something like:
<input type="text" model="sn_number; id" >
You cannot, but there are some workarounds.
1. Use ngChange to update the other model
<input type="text"
ng-model="sn_number"
ng-change="id=sn_number"/>
2. You could watch a model, and when in changes, update another
$scope.$watch('sn_number', function(v){
$scope.id = v;
});
You would need to watch also for changes in id if you want to keep them in sync.
Example here
You can bind fields immediately, not only in ng-change, and actually it isn't data binding, its only angular expression
<label>Name</label>
<input type="text" ng-model="name" value="{{name}}"/>
<label>Key</label>
<input type="text" ng-model="key" value="{{key=name}}" />
It would make no sense to bind an input to two variables in the model. Binding works both ways, so if the model is updated, the field is updated and vice-versa. If you were to bind to two variables, what would be the single source of truth?
However you can use ng-change to call a method on the controller which can set two variables when the field changes.
with ng-init
<div ng-controller="ctrl" ng-init="model = { year: '2013', month:'09'}">
or
<div ng-repeat="c in contact" ng-init="likes = { food: 'steak', drink:'coke'}">

Resources