Passing ng-model from parent view to ng-include template - angularjs

How can i pass a model defined in an controller to ng-include template?
For example: i have a model in my controller's $scope named "account". In the view i am referencing another template for address input.
the address template is below:
<div class="form-group col-lg-12">
<label>Street Address</label>
<textarea ng-model="physicalAddress.AddressLine1" class="form-control">dfdsf</textarea>
</div>
<div class="form-group col-lg-6">
<label>Town / City</label>
<input type="text" class="form-control" ng-model="address.city">
</div>
<div class="form-group col-lg-6">
<label>State / Region</label>
<input type="text" class="form-control" ng-model="address.region">
</div>
<div class="form-group col-lg-6">
<label>Postal / Zip Code</label>
<input type="text" class="form-control" ng-model="address.postalCode">
</div>
In the template above I want to add the physicalAddress object to my "account" model which is defined in the controller of parent view. The only way I see achieving this is by explicitly adding the address prefix address.physicalAddress.AddressLine1. However, this will defeat the purpose of having an template, because i want to be able to use the address template with other objects (shop,user etc).
is there any alternative way of achieving this?

Related

Nested directives with transclusion

I have a set of form directives in which duplicate code can be extracted into a separate directive.
I know that I can use transclusion, but have not been able to identify any technique that allows this (element cloning or passing functions). Tutorials on pluralsight, sitepoint and few other describe extraction into a directive inside the current directive, but I have not been able to apply them to my use case.
Brief Synopsis:-
Two sample directives
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
<div class="form-group">
<label ng-show="visible">Input:
<input ng-model="person.name" type="text" required>
</label>
<p ng-show="!visible"> {{person.name}} </p>
</div>
</div>
And
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
<div class="form-group">
<label ng-show="visible">Input:
<select> <option value="volvo">Volvo</option> .... </select>
</label>
<p ng-show="!visible"> {{person.name}} </p>
</div>
</div>
I wish to condense them into directives like
<my-input-box ng-model="person.name" required></my-input-box>
<my-select-box options = "person.options"></my-select-box>
where my-input-box template is
<my-wrapper-box><input ng-model="person.name" type="text" required></my-wrapper-box>
and my-select-box template is
<my-wrapper-box><select>......</select></my-wrapper-box>
Please see this plunker: http://plnkr.co/edit/k6LWjn?p=preview
How do I extract the wrapper box so that 2-way binding is maintained with the ng-model and overriding attributes like required, bootstrap classes, validation regex, etc. in either the my-wrapper-box or the transcluded HTML element?
Many thanks to all who have read the question. I look forward to your suggestions.
Plunker.
I've added the following to myInputBox directive:
controller: function(){},
bindToController: true,
controllerAs: 'ctrl',
and changed the html to
<my-wrapper-box>
<input type="text" ng-required="reqd" ng-model="ctrl.value" />
</my-wrapper-box>

AngularJS Multiple Transclusion

I have an AngularJS directive with multiple transclusions and one transclusion slot is wrapped by a form.
Everything is working fine except for the form validation messages.
The directive template:
<ng-form name="nbcardform" ng-submit="submit()" novalidate>
<ng-transclude ng-transclude-slot="back"></ng-transclude>
<div class="row">
<div class="col-xs-12">
<button type="submit">Save</button>
</div>
</div>
</ng-form>
Here is an example of the directive usage:
<nb-card>
<nb-card-back>
<input type="text" name="username" ng-model="vm.username" required>
<div ng-messages="nbcardform.username.$error" role="alert">
<div ng-message="required">Required field</div>
</div>
</nb-card-back>
<nb-card>
For some reason the expression nbcardform.username.$error is undefined.
Can someone help me with this?
You should be creating a subform in your directive as it's scope is (likely?) different and it has no idea what nbcardform is.
<nb-card ng-form="myDirectiveForm">
<nb-card-back>
<input type="text" name="username" ng-model="vm.username" required>
<div ng-messages="myDirectiveForm.username.$error" role="alert">
<div ng-message="required">Required field</div>
</div>
</nb-card-back>
<nb-card>
This will still wire in nicely and in the parent directive you could use something like this:
<ng-form name="nbcardform" ng-submit="submit()" novalidate>
<ng-transclude ng-transclude-slot="back"></ng-transclude>
<div class="row">
<div class="col-xs-12">
<button type="submit">Save</button>
</div>
</div>
{{ nbcardform.$valid }}
{{ nbcardform.myDirectiveForm.$valid }}
{{ nbcardform.myDirectiveForm.username.$valid }}
</ng-form>
Have you tried:
<div ng-messages="vm.username.$error" role="alert">
The transcluded content uses the outer scope unless you specify a different scope to the transclude function in your linking function. See "Providing your own Transclusion Scope" here. Note that once you do that, you may no longer be able to reference vm.

How can i add validation ng-maxlength into ng-repeat with error message?

I have a simple code :
<div class="row" ng-repeat="aDiagnosis in diagnosisListForPrescription">
<div class="col-md-4 padding-right-zero" id={{aDiagnosis.rowIndex}}>
<input class="form-control" name="aDiagnosisName" ng-model="aDiagnosis.Name" ng-disabled="true">
</div>
<div class="col-md-4 padding-right-zero form-group" show-errors id={{aDiagnosis.rowIndex}}>
<input class="form-control" name="aDiagnosisResult" ng-maxlength="200" ng-model="aDiagnosis.Result" />
<p class="help-block" ng-if="form.aDiagnosisResult.$error.maxlength">Too Large</p>
</div>
</div>
and use $scope.form.$valid to generate the error message.
But problem is since use ng-repeat every time it finds the same name and when i want to generate second list by clicking a button ,,first error message is gone and error-message now works on the second text (obviously).
So How can i generate error-message each and every time dynamically ,,so every text form in ng-repeat,it has it's own error-message.
You can generate dynamically name attribute of your inputs in ng-repeat. For example, you can put $index (or id of your objects or whatever you want) to generate unique name for your inputs.
<div class="row" ng-repeat="aDiagnosis in diagnosisListForPrescription">
<div class="col-md-4 padding-right-zero" id={{aDiagnosis.rowIndex}}>
<input class="form-control" name="aDiagnosisName-{{$index}}" ng-model="aDiagnosis.Name" ng-disabled="true">
</div>
<div class="col-md-4 padding-right-zero form-group" show-errors id={{aDiagnosis.rowIndex}}>
<input class="form-control" name="aDiagnosisResult-{{$index}}" ng-maxlength="200" ng-model="aDiagnosis.Result" />
<p class="help-block" ng-if="form['aDiagnosisResult-' + $index].$error.maxlength">Too Large</p>
</div>
</div>
Example on plunker.

AngularJS Validation - ng-messages-multiple not displaying multiple errors

All,
I am working on an AngularJS form and am trying to see how the ng-messages directive works with ng-messages-multiple. I can't seem to get it to pick up multiple errors. I expect to see both the required and minimum errors at the same time but for some reason I only see required, then minimum. I posted the HTML below. I have the ng-messages included using bower, the script call in my index.html page, and I am injecting into my app.js module as required.
I am using AngularJS v1.3.2 in this project.
<div class="panel panel-default">
<div class="panel-heading">
<h1>Validation Test Form</h1>
</div>
<div class="panel-body">
<form class="form" name="form" role="form" ng-submit="submit(form)">
<div class="row">
<div class="form-group" show-errors>
<label for="name">Name:</label>
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
minlength="5"
required/>
<div ng-messages="form.name.$error" ng-messages-multiple class="has-error">
<div ng-message="required">Required!</div>
<div ng-message="minlength">Minimum length is 5</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<button class="btn btn-success" type="submit">Save</button>
</div>
</div>
</form>
</div>
<div class="panel-footer">
{{formError}}
</div>
</div>
Try to use ng-minlength instead minlength
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
ng-minlength="5"
required/>
instead
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
minlength="5"
required/>
EDIT
It is normal behaviour for ng-minlength directive, this directive validate only when we have not 0 size of input, entered a value it must be at least 5 characters long, but it's ok to leave the field empty, and, unfortunately, in anyway you don't achieve, that you want. I offer you to create your custom directive or see in direction ng-pattern directive with need behaviour, if you very want that showing two message.

Unique identifiers in dynamic form (ng-repeat)

I have a form with input texts that are looped in a ng-repeat.
For every input field there is a switch with which the user sets "Use default value" to YES/NO.
Every row of input fields are basically two fields, with one hidden one at a time, whether you want to show the default value (switch: YES, input text = disabled) or set a custom value (switch: NO)
I need each element to have a unique identifier to be able to save it on submit, for example **id="title_{{spec.id}}".
The switches work so that the switch-variable is used to create 2way binding, but it is the value of the checkbox within the Switch-DIV that will be saved to the database.
What I think I need to do is apply the spec.id value to the switch-variable="useDefaultValue_{{spec.id}}" and set the same value to the ng-show="useDefaultValue_{{spec.id}}" and ng-hide, but I don't know how to.
HTML:
<div class="row form-group" ng-repeat="spec in specsList">
<div class="col-xs-6 col-md-6">
<label for="specification_">{{spec.title}} <span ng-show="spec.unit.length">({{spec.unit}})</span></label>
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" placeholder="Not visible" ng-model="spec.value" ng-hide="useDefaultValue">
<input class="form-control" type="text" ng-model="spec.defaultValue" ng-show="useDefaultValue" disabled>
</div>
<div class="col-xs-6 col-md-6">
<label for="useDefaultValue_">Use default value</label> - {{spec.useDefaultValue}}<br />
<div class="switch" init-switch switch-variable="useDefaultValue">
<input type="checkbox" id="useDefaultValue_{{spec.id}}" name="useDefaultValue_{{spec.id}}" ng-model="spec.useDefaultValue">
</div>
</div>
</div>
Since your checkbox is backed by the row-dependent spec.defaultValue, you can come up with a simpler solution and don't need the switch. Just reference spec.useDefaultValue instead of your current useDefaultValue to directly access it.
<div class="row form-group" ng-repeat="spec in specsList">
<div class="col-xs-6 col-md-6">
<label for="specification_">{{spec.title}} <span ng-show="spec.unit.length">({{spec.unit}})</span></label>
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" placeholder="Not visible" ng-model="spec.value" ng-hide="spec.useDefaultValue">
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" ng-model="spec.defaultValue" ng-show="spec.useDefaultValue" disabled>
</div>
<div class="col-xs-6 col-md-6">
<label for="useDefaultValue_">Use default value</label> - {{spec.useDefaultValue}}<br />
<input type="checkbox" ng-model="spec.useDefaultValue">
</div>
</div>
As an aside, I would also use ng-if instead of ng-show and ng-hide to lighten the page and make the transitions smoother.
EDIT Submit function :
$scope.submit = function() {
angular.forEach(specsList, function(spec, index) {
if (spec.useDefaultValue) {
$scope.user[spec.title] = spec.defaultValue;
}
else {
$scope.user[spec.title] = spec.value;
}
});
User.save(user).$promise.then(function(persisted) {
// do some post-save cleanup
});
};
Of course, this is assuming you save spec values on the user. They could be stored somewhere else.

Resources