What's a good practice when building forms dynamically in AngularJS? - angularjs

I've got some JSON data- an Array of Fields containing Input Type (input, dropdown, radio, checkbox, etc.), Label and whether they are required or not.
I'm doing an ng-repeat through the array to build the form. I'm trying to understand what's the best way to build different kinds of inputs based on the Input Type value.
In normal programming, I would do a
foreach (var field in FormData){
if (field.inputType == "dropdown"){
//logic to build dropdown using jQuery, etc..
}
}
In AngularJS, I can't really do if thens within an ng-repeat="field in FormData". What's the proper way to dynamically build out these different kinds of elements while looping through an array?
This question is very similar:
How can I use Angular to output dynamic form fields?
Many thanks for any suggestions.

In my application, I did use an ng-switch (see the answer from the very similar question) in my ng-repeat to achieve something similar to this. The only problem with this is to link to the model. If you want to bind to a property name that is stored in a variable (if you json contains an id for the field), you won't be able to something like this :
<input type="text" ng-model="formdata.{{elem.id}}" />
I found that you can do this instead :
<input type="text" ng-model="formdata[elem.id]" />

Related

Obtaining the input box within an ng-repeat for styling purposes

I am trying to obtain the textbox that is assigned to data via a ng-repeat in order to validate data via javascript (e.g. if it is an E-mail etc).
The below is something similar i am working with:
<input class="form-control"
ng-if="key.sch_input_type == 'text'"
type="vm.data[key.input_type]"
class="form-control"
ng-model="vm.data[column_name]"
ng-change="vm.updateRecord(data)">
I am aware there is the angular validation library available to use but because of the way the code is currently, type is used for another purpose (in this case text) so i cannot set it to what I require and so I am doing it via Javascript using RegEx. i.e. if it is not email for example, the textbox should highlight red.
Is there a way I can obtain the textbox in question or a better way to do this?

What's the best way to reduce repetition of form element attributes in angularjs?

I'm designing an AngularJS 1.5.x app that will have lots of forms and lots of fields per form. I'm finding that I'm repeating attributes a lot, e.g.:
<div class="form-group">
<label class="control-label" for="thing.Field1">Field 1</label>
<input class="form-control ctrl-md"
type="text"
id="thing.Field1"
name="Field1"
ng-model="thing.Field1"
ng-maxlength="30"
required
uib-tooltip="Field 1 is required"
tooltip-placement="right"
tooltip-trigger="none"
tooltip-is-open="thingForm1.Field1.$invalid && showValidationErr('Thing1')"
ng-blur="fieldBlur('Thing1')">
</div>
I've attempted to use a directive + template, and it works more or less, but it seems very complex and slow.
Is there a good way to make the input reusable? Or should I just get used to doing a lot of copy+paste in my editor?
In addition to reducing repetitive coding, it would be nice to be able to change all elements in one place, in the case that I want to change the tooltip position on all fields for example.
There is many ways. Have a look at this library http://angular-formly.com/. In my projects I use plain inputs and writing directives only in a complex cases, like 2 field controls. Or special field like card expiration date.
UPDATE
Ok, have a look at this pls. Angular: better form validation solution
You have 3 solutions:
To store your attributes as it is.
To store a group of attributes, commonly used together, in a directive. Or use directive which utilize array of properties. Like validation directive in my example.
To use directive with transclusion to utilize 1st and 2nd approach. So you can swap elements position (such as label, input control, error hint) in a single place. Plus you can easily create property like... preset on this directive and store attribute presets in it.
So, as I already told, there is many ways to reduce number of attribute repetition.

angularjs multilingual text field with ngmodel

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.

Dynamic data-binding in AngularJS

I'm building an AngularJS app and I have ran into an issue. I have been playing with the framework for a while and I have yet to see documentation for something like this or any examples. I'm not sure which path to go down, Directive, Module, or something that I haven't heard of yet...
Problem:
Basically my app allows the user to add objects, we will say spans for this example, that have certain attribute's that are editable: height and an associated label. Rather than every span have its own dedicated input fields for height and label manipulation I would like to use one set of input fields that are able to control all iterations of our span object.
So my approx. working code is something like this:
<span ng-repeat="widget in chart.object">
<label>{{widget.label}}</label>
<span id="obj-js" class="obj" style="height:{{widget.amt}}px"></span>
</span>
<button ng-click="addObject()" class="add">ADD</button>
<input type="text" class="builder-input" ng-model="chart.object[0]['label']"/>
<input type="range" class="slider" ng-model="chart.object[0]['amt']"/>
The above code will let users add new objects, but the UI is obviously hardcoded to the first object in the array.
Desired Functionality:
When a user clicks on an object it updates the value of the input's ng-model to bind to the object clicked. So if "object_2" is clicked the input's ng-model updates to sync with the object_2's value. If the user clicks on "object_4" it updates the input's ng-model, you get the idea. Smart UI, essentially.
I've thought about writing a directive attribute called "sync" that could push the ng-model status to the bound UI. I've though about completely creating a new tag called <object> and construct these in the controller. And I've thought about using ng-click="someFn()" that updates the input fields. All of these are 'possibilities' that have their own pros and cons, but I thought before I either spin out on something or go down the wrong road I would ask the community.
Has anyone done this before (if so, examples)? If not, what would be the cleanest, AngularJS way to perform this? Cheers.
I don't think you need to use a custom directive specifically for this situation - although that may be helpful in your app once your controls are more involved.
Take as look at this possible solution, with a bit of formatting added:
http://jsfiddle.net/tLfYt/
I think the simplest way to solve this requires:
- Store 'selected' index in scope
- Bind ng-click to each repeated span, and use this to update the index.
From there, you can do exactly as you proposed: update the model on your inputs. This way of declarative thinking is something I love about Angular - your application can flow the way you would logically think about the problem.
In your controller:
$scope.selectedObjectIndex = null;
$scope.selectObject = function($index) {
$scope.selectedObjectIndex = $index;
}
In your ng-repeat:
<span ng-repeat="widget in chart.object" ng-click="selectObject($index)">
Your inputs:
<input type="text" class="builder-input" ng-model="chart.object[selectedObjectIndex]['label']"/>
<input type="range" class="slider" ng-model="chart.object[selectedObjectIndex]['amt']"/>

How do I structure AngularJS directive for compound form fields?

I would like to use AngularJS for some administration forms. It's very easy to bind view and model. I also like how you can add validation. But when I tried to prevent redundant code by introducing directives I hit a border. Could you please help me how I should structure code with AngularJS for this problem:
In my forms I have some compound fields. For example you can choose a country in a dropdown. Next to that dropdown you can enter a city in a textfield. When you choose another country the city name should be cleared. That's easy. Now I want autocompletion in the city textfield. When you enter a few characters you get suggestions for cities in the selected country. The autocompletion widget is the minor problem here, let's for simplicity say I would use JQueryUI for that.
I already managed to implement simple directives. My questions are:
1.) I like the functionality for validation in NgModelController. Can I somehow reuse this in my directive? It would be nice if I could add a "required" attribute to my directive. If it is set then all compound fields are required.
2.) How would I connect the directive with the surrounding model? For example I would like to edit a customer in an administration form and my "address" directive should display and edit the customer address.
3.) How would I connect the directive with my city lookup service? I need to give country and first typed letters of city to my service. Result is a list of city names that can be displayed in the autocompletion widget.
Here is the plunker that show you how to set require attribute.
Main idea is having required="{{isRequired}}" in the template and having isRequired as attribute for your directive.
template: '<input name="city" type="text" ng-model="city" placeholder="City" required="{{isRequired}}">'

Resources