AngularJS Directive Nested Models - angularjs

I have the following code
<my-template title="Client Profile">
<my-section name="personalInfo" title="Personal Informations">
<p>Please enter your personal informations</p>
<my-field type="text" name="firstName" label="First Name">
<my-field type="text" name="lastName" label="Last Name">
</my-section>
<my-section name="demographicInfo" title="Demographic Informations">
<p>Hello {{ personalInfo.firstName }}, where are you from?</p>
<my-field type="text" name="country" label="Country">
<my-field type="text" name="city" label="City">
</my-section>
<p class="output">
{{ personalInfo.firstName }} {{ personalInfo.firstName }} is from
{{ demographicInfo.city }}, {{ demographicInfo.country }}.
</p>
</my-template>
As you see there are 3 directives: myTemplate, mySection and myField. I've tried different ways to implement this but I couldn't manage to make it work. The easiest way will be to use full model names everywhere. I try to avoid this to make the syntax easier because the client will edit this templates.
Could you provide me a quick-n-dirty example on how to implement this?
Edit
I've made some progress on this but still I have to write {{ values.section.field.value }} instead of {{ section.field }}. Check it out here http://plnkr.co/edit/YKFanoJ1XE4BTgYJn1xd?p=preview
I still have several questions
Is it possible to use the shorter names for variables?
Is it possible to use variable directly inside the section without specifying the section name? (if I am in the personalInfo section I would like to be able to write {{ firstName }} instead of {{ personalInfo.firstName }})

Since nobody answered this question I will accept my partial solution.
Check it out here http://plnkr.co/edit/YKFanoJ1XE4BTgYJn1xd?p=preview

Related

Elegant solution for a dynamic ng-repeat form

I am new to AngularJS and I have following problem:
I want to iterate over an array of 'attributes' with a bunch of keys for the values stored in the Object.
<div ng-repeat="key in attributes">
{{key}}: <input type="text" value={{Object.key}} name="{{key}}">
</div>
This code displays just the correct key of {{column}} but delivers no result for the value of {{Object.column}}.
The phrase {{Object.{{column}}}} dosn't work neither.
If I run the code, giving the Object a static key of (e.g. ID) everything works perfectly.
I could go for
<div>
id: <input type="text" value={{Object.id}} name="id">
name: <input type="text" value={{Object.name}} name="name">
value: <input type="text" value={{Object.value}} name="value">
and so on...
</div>
But this static form does not seem to be the perfect solution.
Can someone help me?
You should do something like this -
<div ng-repeat="key in attributes">
{{key}}: <input type="text" value={{ Object[key] }} name="{{ Object[key] }}">
</div>
Use {{Object[key]}}. Angular considers .key to be a constant not a variable.

AngularJS - get label text for field

Question
I was wondering what the AngularJS "best practice" way of getting a label for a field is. With jQuery you just query using a "label for" query then extract the text. While it's possible to do it this way with AngularJS, something just doesn't feel right about it.
Assume you have something like this in your HTML:
<form name="MyForm" ng-controller="Ctrl">
<label for="MyField">My spoon is too big:</label>
<input type="text" size="40" id="MyField" ng-model="myField" />
<br /><br />
You entered {{ myField }} for {{ myField.label }}
</form>
The controller internal is pretty simple:
$scope.myField = 'I am a banana.';
Basically I want to populate the myField.label in the output with "My spoon is too big."
What I'm Doing Now
All I am doing right now is executing a query that pulls the data similar to the jQuery methodology ($("label[for='MyField']")). Then, if that doesn't exist I am just pulling the placeholder text. It works, but it seems like a bit of overhead.
What I'm Trying to Accomplish
I want some custom form validation and I want to include the label in the message. I just need to pull the label text so that I can write it extremely generically and then not have to worry about people switching i18n data in dynamically later in the game.
Fiddle
Per the suggested solution:
https://jsfiddle.net/rcy63v7t/7/
You change your HTML to the following:
<label for="MyField">{{ myFieldLabel }}</label>
<input type="text" size="40" id="MyField" ng-model="myField" />
and your JS to the following:
$scope.myFieldLabel = 'My spoon is too big:';
then later, you can get/set its value just as easily:
if ($scope.myFieldLabel === 'My spoon is too big:') {
$scope.myFieldLabel = 'New label:';
}
Note that new AngularJS best practices call for always using a "dot" in a field reference. It would fit perfectly here if you did something like:
<label for="MyField">{{ myField.label }}</label>
<input type="text" size="40" id="MyField" ng-model="myField.value" />
and JS:
$scope.myField = {
value: '',
label: 'My spoon is too big:'
};
Then you can always easily access $scope.myField.label and $scope.myField.value.
Let's say in your controller you have a scope variable like
$scope.myField = {};
$scope.myField.label = "Fruit name";
and your template is like
<form name="MyForm" ng-controller="Ctrl">
<label for="MyField">{{myField.label}}</label>
<input type="text" size="40" id="MyField" ng-model="myField.value" />
<br /><br />
You entered {{ myField.label }} for {{ myField.label }}
</form>
By this field label will come dynamically. Apply custom validation in input field as per your requirement.
Hope I understand exactly what you wants.
Just put your label text in the input title and you can use a "#" directive. You can also use this to make sure the label id matches.
<label for="{{myfield_control.id}}">{{myfield_control.title}}</label>
<input type="text" size="40" id="MyField" ng-model="myField" title="My spoon is too big:" #myfield_control >
<br /><br />
You entered {{ myField }} for {{ myfield_control.title }}
myField is your ngModel. myfield_control is a reference to your input control.

AngularJS add incremental value

Is it possible to add an incremental identifier to ng-model in AngularJS?
I'm iterating a list of items, and need to and an incremental value to the ng-model="" attribute for each item in the loop, or if there is a simpler way, I'd like to hear it.
What I'm currently trying:
<li ng-repeat="recipe in recipes">
<label for="cost_ingredient_{{recipe.ingredient_id}}" style="font-size: 16px;">{{recipe.ingredient}}</label>
<input ng-model="{{recipe.model_name}}" name="formcost_ingredient_{{recipe.ingredient_id}}" type="number" id="cost_ingredient_{{recipe.ingredient_id}}" min="0" step="0.01" value="0" />
</li>
I tried doing this with a directive, but when I call 'formData' in the controller, none of the model indices come up.
I need to pass this information, as part of a form submission back to the next page in the process. This will be deployed to Android, so I'm thinking of just adding this to window.sessionStorage as I only need this once for every time a user runs my app.
Try using $index property to generate unique ID:
<div ng-repeat="item in items">
<span id="unique_ID_{{ $index }}">{{ item }}</span>
</div>
http://plnkr.co/edit/SPeyIb2dGxPpL3yKykr6?p=preview
On iteration, attach an id in the repeater with ng-init. This will modify your original structure and the id will be available outside the repeater.
<li ng-repeat="recipe in recipes" >
<label ng-init="recipe.someId = $index" for="cost_ingredient_{{recipe.someId}}" >
{{recipe.ingredient}}
</label>
<input ng-model="{{recipe.model_name}}" name="formcost_ingredient_{{recipe.someId}}"
type="number" id="cost_ingredient_{{recipe.someId}}"
min="0" step="0.01" value="0" />
</li>
This is similar to Michal Stefanow's answer, except here you actually change the structure by adding an attribute to each item, in this case it's called someId
Another way:
<li ng-repeat="recipe in recipes" >
<label ng-init="recipe.costIngredient = 'cost_ingredient_' + $index" for="{{recipe.costIngredient}}" >
{{recipe.ingredient}}
</label>
<input ng-model="{{recipe.model_name}}"
ng-init="recipe.formcostIngredient = 'formcost_ingredient_' + $index" name="{{recipe.formcostIngredient}}"
type="number" id="{{recipe.costIngredient}}"
min="0" step="0.01" value="0" />
</li>
What you'd really want is to pre-process this on the JavaScript side so that it's not evaluated every time:
$scope.recipes = [ your array here ];
angular.forEach($scope.recipes, function(recipe, index){
recipe.costIngredient = 'cost_ingredient_' + index;
recipe.formcostIngredient = 'formcost_ingredient_' + $index;
});
then iterate over that.
P.S. you may want to look into using ng-bind rather than {{ }} to generate the HTML, it's better for unforeseen errors

Assigning AngularJS model inside ngRepeat

I would like to iterate over an array in AngularJS like this:
var languages = ['en', 'es', 'fr'];
To generate something like this:
<input type="text" ng-model="mymodel.en" placeholder="Name (EN)">
<input type="text" ng-model="mymodel.es" placeholder="Name (ES)">
<input type="text" ng-model="mymodel.fr" placeholder="Name (FR)">
I have tried this:
<div ng-repeat="language in languages">
<input type="text" ng-model="mymodel.{{language}}" placeholder="Name ({{language | uppercase}})">
</div>
But throws an error:
"Syntax Error: Token '{' is an unexpected token at column ..."
How should I perform this loop?
Use mymodel[language] instead of mymodel.{{language}}
<div ng-repeat="language in languages">
<input type="text" ng-model="mymodel[language]" placeholder="Name ({{language | uppercase}})">
</div>
plnkr
See the plnkr, and start typing in any of the input fields to see the model changes.
you cantry something like this,
<input type="text" ng-model="mymodel[language]" ...
You shouldn't use {{}} notation inside ng-model here you can refer to your property in the mymodel object.
But it seems that you are trying to get binding via model somehow for your inputs. It's not gonna work in your case because you need to init mg-model directives.
For catching changed in your model from dynamically generated you need to compile used directives using $compile service.
Here you can check out sample. I googled it but I've solved similar problem in similar way.

Angular DRY Templates

I am new to angular and I realized that there is a lot of duplicated code in my templates, for example for a single field.
What is the best way to make the templates DRY. I would like to avoid to concatenate strings in some helper functions.
<div class="form-group">
<label for="Name">
{{'Name'|i18n}}: <span class="required">*</span>
</label>
<input type="text" class="form-control" ng-model="schema.Name" id="Name" name="Name" placeholder="{{'Name'|i18n}}" maxlength="100" required />
<div ng-show="(submitted || form.Name.$dirty) && form.Name.$invalid">
<span class="validation-text">{{'Required'|i18n:'i18n.Name'}}</span>
<span class="validation-arrow"></span>
</div>
<div class="form-hint">{{'NameHint':i18n}}</div>
</div>
For example, in ASP.NET MVC there are a lot of helper functions, would be nice to something similar, where I can use e.g.:
textBox('schema.Name', { required: true, maxlength')
hint('schema.Name')
You can use custom directives to reduce the repetition, at the cost of scattering. If really all you need is to include a snippet then the include directive should do the job.
<ng-include src="views/foo.html"/>

Resources