angular2 capture info from dynamically generated inputs - possible? - javascript

Working on an update form which I would like to generate and capture inputs for a variable sized array
The current unhappy version only supports the first three statically defined elements in the constituency array. So the inputs look like this...
<input #newConstituency1 class="form-control" value={{legislatorToDisplay?.constituency[0]}}>
<input #newConstituency2 class="form-control" value={{legislatorToDisplay?.constituency[1]}}>
<input #newConstituency3 class="form-control" value={{legislatorToDisplay?.constituency[2]}}>
and the function to update pulls the values of the form using the static octothorpe tags.
updateLegislator(newConstituency1.value, newConstituency2.value, newConstituency3.value)
But this doesn't allow for a variable sized Constituency array.
I am able to use *ngFor directive to dynamically create input fields for a theoretically infinitely sized constituency array:
<div *ngfor constit of legislatorToDisplay?.constituency>
<input value={{constit}}>
</div>
but have not successfully been able to capture that information thereafter. Any kind assistance would be greatly appreciated.

You just have to have a form object in your component that matches the HTML input components that were created.
Template
<div *ngfor constit of legislatorToDisplay?.constituency>
<input value={{constit}} formControlName="{{constit}}">
</div>
Component
/* create an empty form then loop through values and add control
fb is a FormBuilder object. */
let form = this.fb.group({});
for(let const of legislatorToDisplay.constituency) {
form.addControl(new FormControl(const))
}

Use two-way data binding:
<div *ngFor="constit of legislatorToDisplay?.constituency; let i = index">
<input [(ngModel)]="legislatorToDisplay?.constituency[i]">
</div>

Related

How can I get user input with HTML to handle in JS?

My website has a bunch of rows (as many as the user needs) consisting of two fields. I want the user to fill in all the fields, and submit them. However, I believe this can all be handled client-side, since I want to use the field values in javascript code.
this is the html code:
<div class="players">
<div id="wrapper">
<span>Name: <input type="text"> Dex modifier: <input type="text"></span>
</div>
<input type="button" value="add player" onclick="add_fields()">
<input type="button" value="submit" onclick="submit()">
</div>
and my javascript function
function add_fields() {
document.getElementById("wrapper").innerHTML += '<br><span>Name: <input type="text"> Dex modifier: <input type="text"></span>\r\n'
}
I need a way to get all of the form values (right now with an unwritten function submit()) and store them as variables.
It is good practice to use a <form> element when handling multiple inputs simultaneously. The form element can access all of the inputs it has inside of it. This way you won't have to select each individual input but can select and process them all together.
So start with the form wrapping. Then instead of listening for the onclick on the <input type="button" value="submit" onclick="submit()">, listen for the submit event on the form element.
It is considered best practice to listen to events by using the .addEventListener() method. This way you can set multiple event handlers to a single event without overwriting the onclick or onsubmit property of an element. Chris Baker does an excellent job explaining it in this SO post.
So now that you have a form, how do we get the data out of it? You could use the modern class of FormData. FormData creates an iterable object, which means we can loop over it using for..of, that holds all the names and values of the inputs in a form. It also has methods to add, remove and get the keys or values from the object. The FormData constructor can take a <form> element as argument like so:
var formElement = document.querySelector('form'); // Select the form.
var formData = new FormData(form); // Pass the form into the FormData class.
Now the formData variable holds all of the names and values of the form.
I've added a working example for you to try out. Please read up on the documentation I provided you to understand what is going on and what you can do with it.
Quick sidenote: FormData and the for..of loop are relatively new and are not supported in IE. If that is a dealbreaker I would suggest you don't use the FormData constructor and simply loop over the elements within the form.
Edit: I changed to loop from formData.values() to formData to get both the name and value attributes of each input. This is identical to formData.entries() as show in the MDN documents.
// Create storage for the values.
var values = [];
// Get the form element.
var form = document.getElementById('form');
// Add the submit event listener to the form.
form.addEventListener('submit', submit);
function submit(event) {
// Get the data from the form.
// event.target represents the form that is being submitted.
var formData = new FormData(event.target);
// Loop over each pair (name and value) in the form and add it to the values array.
for (var pair of formData) {
values.push(pair);
}
// Log the values to see the result.
console.log(values);
// Prevent the form from default submitting.
event.preventDefault();
}
<div class="players">
<!-- Wrap a form around the inputs -->
<form id="form">
<div id="wrapper">
<span>Name: <input type="text" name="name"> Dex modifier: <input type="text" name="dex"></span>
</div>
<input type="button" value="add player" onclick="add_fields()">
<!-- Notice type="submit" instead of type="button". This is important -->
<input type="submit" value="submit">
</form>
</div>
You need to be able to get the values of the dynamically added input elements.
First, you need to add them in a way you can separate them. So, providing each pair an exclusive parent is necessary.
document.getElementById("wrapper").innerHTML += '<div id="aparent"><br><span>Name: <input type="text" id="name"> Dex modifier: <input type="text" id="dex"></span><div>\r\n'
Now, get all the parent elements and iterate through them to fill an array of "name" and "dex-modifier" pairs. Use a library like JQuery for easy DOM manipulation. This seems to be your "submit" function.
var userData = [];
//Iterate all the parents
$('#aprane').each(function() {
//Get the values of each pair and put them in an array
userData.push({name: $(this).children('#name').val(), dex: $(this).children('#dex').val()}
})

Add new key value pair in Angular Dynamic Form

I have a requirement in Angular Dynamic Form to add key-value pair on click of add button.Both key and value should be editable
a)- Key either we can select from master list or it can be a free textbox(if value is not available in master list then autocomplete should be replaced by textbox).
b)- Value should be a textbox.
Also, There should be a nearby save button and delete button along with above fields to either submit it or delete it.
As per current implementation in our project,'key' is always hardcoded and 'value' is editable inside form group.
What should be the best approach to add a new key-value pair in dynamic form?
1- Should we need to create a new form group for adding new row?
2- Utilize the current approach and extend the functionality on it in same form group
Any approach/leads will be most welcome.
1 .On button click create a function that create form group and add to form array in your parent FormGroup
For put key values like this
let r=this.fb.group({mvl:"keey",sec:"val"});
Mark your input readonly to make it non edible
foo:FormGroup
constructor(public fb:FormBuilder) {
this.foo=this.fb.group({
string :"",
number:0,
common1:this.common,
common2:this.common,
multi:this.fb.array([])
});
}
add()
{
let r=this.fb.group({mvl:"keey",sec:"val"});
(this.foo.get("multi") as FormArray).push(r);
}
Inside your form put html like this
<div formArrayName="multi">
<div *ngFor="let el of multiForm;let i=index" [formGroupName]="i">
<input type="text" matInput placeholder="mvl{{i}}" formControlName="mvl">
<input type="text" matInput placeholder="sec{{i}}" formControlName="sec">
</div>
<div (click)="add()">add</div>
</div>

How to submit data from input fields generated using ng-repeat and get the value of all the input fields?

I am new to Angular js and I need to create a form where the input fields will be dynamically generated based on a loop and I need to send all the field's data to an API.
This is the string that I get from the backend
"Earth:planet,life,solar,global$##data_col.signal:gateway ox,gw ox,gateway all ox,all sig,,gw signal gain,gateway"
This is my part of the html below where I process the string
<div class="container-fluid synBox">
<span><b>Enter synonyms:</b></span>
<form enctype='application/json'>
<div class="form-group" name="syn" ng-repeat="n in message.expert_advice.split('$##')">
<span class="fonts" style="color:#487baa;"><b>{{n.split(":")[0]}}</b></span>
<input class="form-control" id="expert_advice_input" type="text" ng-model={{n.split(":")[1]}} placeholder="" name={{n.split(":")[0]}} value={{n.split(":")[1]}}>
</div>
<button type="submit" class="btn btn-primary center-block" ng-click="submit_synonyms()">Submit</button>
</form>
</div>
Here is my js for the function in onclick submit_synonyms()
$scope.submit_synonyms = function() {
var variable = document.getElementById('expert_advice_input').value;
console.log(variable)
}
Here is what it looks like in the UI
I was hoping that I would get the value for all input fields but when I click the button I only get the value of the first input field (as seen in the console).
planet,life,solar,global
I also followed other similar questions in stackoverflow like Ng-repeat submit form with generated fields but couldn't figure out how to apply it in my situtation. What am I doing wrong?
Do note that the number of input fields can be dynamic based on the string supplied to me.
ADDITIONAL INFO
Just for the sake of clarity, the reason I am doing the splits on the string is to get the heading and the remaining comma separated strings in the input fields to which a user can add more string and hit the submit button.
write the following in your controller
const param = <input> //"Earth:planet,life,solar,global$##data_col.signal:gateway ox,gw ox,gateway all ox,all sig,,gw signal gain,gateway";
$scope.param = param.split('$##').reduce((acc,val)=> {
const spl = val.split(':');
acc[spl[0]] = spl[1];
return acc;
},{});
and following in your template or html
<ul >
<li data-ng-repeat="(key,value) in param"><label for={{key}}>{{key}}</label><input type='text' value='{{value}}'</li>
</ul>
add styles and optimize code style.

Django formset equivalent in angular.js

Django has formsets, where multiple forms can be used in one big form. So let's say one can add in a e.g. library formset mulitple books (providing the author and title) using repetitions of the same book form.
How to achieve the same functionality with Angular.js and Django Rest Framework? I'm new to Angular.js and Django Rest Framework and need some guidance how to be able to dynamically add more forms(e.g. for a book) for a given model in one big form (e.g. my library) and save them in Django Backend.
You can achieve this in 2 steps:
On Frontend
Create a <form> on your page that will structure the data entered by the user as you need. Inside that <form> element, you'll need to use the ngForm for multiple forms' validation to behave correctly (here is a nice explanation of how ngForm works). A hypothetical code snippet would look like:
<form name="libraryForm">
<div ng-repeat="book in vm.newBooksToAdd">
<!-- ngForm directive allows to create forms within the parent form -->
<ng-form name="bookForm">
<div>
<label>Book title</label>
<input ng-model="book.title" type="text" name="title" required>
</div>
<div>
<label>Author</label>
<input ng-model="book.author" type="text" name="author" required>
</div>
</ng-form>
</div>
</form>
In your controller, you can initialize the list of books to add as vm.newBooksToAdd = []; and whenever you want to add a new form to your list of forms for new books, just vm.newBooksToAdd.push({}) an empty object. Thus, you will send to the backend an array of objects representing books you want to create.
On Backend
Now here you'll need to overwrite the .create() method of your view to allow creating many instances at once, because by default it expects a single object. Your view might look like this:
class LibraryViewSet(views.ModelViewSet):
...
def create(self, request):
serializer = self.get_serializer(data=request.data, many=True) # notice the `many` keywork argument here
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
return Response(serializer.data, status=status.HTTP_201_CREATED)
Note: If you would like to allow both a single instance creation and creation in bulk, you'll need to adjust your .create() method to check for the data type of request.data.
Note 2: There is a django-rest-framework-bulk library that achieves what you want on the backend, but I didn't try it, so cannot say anything bad or good about it.
Good luck!

How to select form input based on label inner HTML?

I have multiple forms that are dynamically created with different input names and id's. The only thing unique they will have is the inner HTML of the label. Is it possible to select the input via the label inner HTML with jQuery? Here is an example of one of my patient date of birth blocks, there are many and all unique except for innerHTML.
<div class="iphorm-element-spacer iphorm-element-spacer-text iphorm_1_8-element-spacer">
<label for="iphorm_081a9e2e6b9c83d70496906bb4671904150cf4b43c0cb1_8">events=Object { mouseover=[1], mouseout=[1]}handle=function()data=Object { InFieldLabels={...}}
Patient DOB
<span class="iphorm-required">*</span>
</label>
<div class="iphorm-input-wrap iphorm-input-wrap-text iphorm_1_8-input-wrap">
<input id="iphorm_081a9e2e6b9c83d70496906bb4671904150cf4b43c0cb1_8" class="iphorm-element-text iphorm_1_8" type="text" value="" name="iphorm_1_8">events=Object { focus=[1], blur=[1], keydown=[1], more...}handle=function()
</div>
<div class="iphorm-errors-wrap iphorm-hidden"> </div>
This is in a Wordpress Plugin and because we are building to allow employees to edit their sites (this is actually a Wordpress Network), we do not want to alter the plugin if possible.
Note that the label "for" and the input "id" share the same dynamic key, so this might be a way to maybe get the id, but wanted to see if there is a shorter way of doing this.
Here I cleaned up what is likely not used...
<div>
<label for="iphorm_081a9e2e6b9c83d70496906bb4671904150cf4b43c0cb1_8">
Patient DOB
<span class="iphorm-required">*</span>
</label>
<div>
<input id="iphorm_081a9e2e6b9c83d70496906bb4671904150cf4b43c0cb1_8">
</div>
You can use the contains selector to select the Patient DOB labels, then find the related input.
$('label:contains("Patient DOB")').parent('div').find('input');
This assumes that the label and input are wrapped in the same div and may not work if more than one pair is in the same div. At least the first part will get you the labels that contain Patient DOB, then you can adjust the later parts to find the correct input element.
For more help on jquery selectors, see the API.
Here is a fiddle demonstrating this.
var getForm = function(labelInnerHtml) {
var $labels = jQuery('label');
$labels.each(function() {
if (jQuery(this).html() == labelInnerHtml) {
var for_id = jQuery(this).attr('for');
return jQuery('#'+for_id);
}
});
return [];
};​​
The class iphorm_1_8 on the input is unique for each form element. So it's simple.
$('.iphorm_1_8');

Categories

Resources