Show a form-field dynamically on option select - javascript

This is my fiddle : DEMO
I am adding the template ID read-only fields, based on selection of option. 1 for SMS, 2 for email etc..
Since there is a provision to add new category, how to dynamically add template IDs to newly added options?
//Adding Template ID based on option
$('#categoryevent').on('click', function() {
$('.actionConfig').empty();
var z = $("#categoryevent option:selected").text();
if (z == 'sms') {
var smsConfig = '<div class=form-group><label class="col-sm-2 control-label"for=templateId>Template ID: </label><div class=col-sm-8><input class=form-control id=templateId name=templateId value="1" readonly="readonly"></div></div>';
$('.actionConfig').append(smsConfig);
}
});

Instead of checking for the textual representation of the option, you should check for the value attribute. Since you did not add the value attributes yet for the options you hardcoded, you will have to do this as well, i.e. change:
<option>SMS</option>
to
<option value="0">SMS</option>
Alternatively, if you don't want to use the standard value attribute (e.g. because you want to avoid default beheviour) you can instead go for <option data-selectionId="1">SMS</option>. Obviously increment the id for each option you have in your select.
Now if you create a new option, you will have to set this data:
var val = $("#new-option-event").val().trim();
var opt = '<option value="'+ globalCounterVariable +'">' + val + '</option>';
globalCounterVariable += 1;
$('#categoryevent').append(opt);
$('#categoryevent').val(val);
$('#new-option-event').val('');
You will have to define a global veriable (actually outside of the scope of the .addevent handler is enough) that you initially will have to set to 3 (the number of hardcoded options).
Now you can do this:
$('#categoryevent').on('change', function() {
var selection = $(this).val(); //this is reference to the changed element, i.e. the select with Id 'categoryeveny'.
var html = '<div class="form-group"><label class="col-sm-2 control-label" for="templateId">Template ID: </label><div class="col-sm-8"><input class="form-control" id="templateId" name="templateId" readonly="readonly"></div></div>';
$(html).find("input").val(selection);
$(".actionConfig").empty();
$('.actionConfig').append(html);
});
Note how I removed the need for all the if clauses, because you did the same logic each branch. Simply parameterize whatever you want to inject and this is all you need.
If you want to show different values for each selection (so different data than 1,2,3,... etc), you will have to either make that an option in the input where you create a new option, or hardcode generic logic in the change event, where you decide what content is shown based on the value of selection.

Welcome to SO,
you can do something like this,
Set value of option as Template-Id 1,2,3 now when you add new category maintain counter and add it as value of newly added option.
Now keep other things same just get template id from option value.
something like this,
var opval = get option value here..
var smsConfig = '<div class=form-group><label class="col-sm-2 control-label"for=templateId>Template ID: </label><div class=col-sm-8><input class=form-control id=templateId name=templateId value="+opval+" readonly="readonly"></div></div>';
$('.actionConfig').append(smsConfig);
Hope this helps.
Edit:
answer jsfiddle

Here is the answer fiddle : DEMOanswer
$('#categoryevent').on("click", function(ev) {
// alert(ev.target.selectedIndex);
var value = ev.target.selectedIndex;
$('.actionConfig').empty();
var z = $("#categoryevent option:selected").text();
z = z.toLowerCase();
var templateId = '<div class=form-group><label class="col-sm-2 control-label"for=templateId>Template ID: </label><div class=col-sm-8><input class=form-control id=templateId value="' + value + '" name=templateId readonly="readonly"></div></div>';
$('.actionConfig').append(templateId);
});

Related

Show/Hide Form elements based on json response

I make an api call and get a json Response that looks like this:
{"Field":"Amount","FieldName":"Amount","FieldType":"Numeric","MaximumLength":128,"MinimumLength":0,"Options":"Mandatory"}
The api call Returns between 5-10 of These objects.
In my html i have the fields inside a form, and they look as follow
<div class="form-group">
<label class="col-md-4 control-label" for="Amount">Amount</label>
<div class="col-md-4">
<input name="amount" class="form-control input-md" id="amount" type="text" placeholder="placeholder">
</div>
</div>
Now, depending on the json repsonse, i Need to show/hide different fields. Additionally, i Need to pass the min and max length, aswell as whether it's required or not ("Options":"Mandatory", in this example) Attributes to html, so the front end is already validate (obviously, further validation will be done server-side).
What's the best way to do this?
Edit:
I hide the Form Elements by using class="hidden". Also, every form element has a class that is identical to the id of the form element.
What i've tried so far is the following:
var ids = [];
for(var item in data) {
ids.push(data[item]['Field']);
$("." + ids[ids.length]).removeClass("hidden");
}
So in the above example, what i was hoping would happen in the first Iteration is that
$("." + ids[ids.length]).removeClass("hidden");
changes to
$(.Amount).removeClass("hidden");
and therefor show the form element.
Thanks
The problem is in this line
$("." + ids[ids.length]).removeClass("hidden");
When you push one element to ids array the length becomes 1 and your element is in 0th position but you are accessing element in first position.
To correct it change the line to
$("." + ids[ids.length - 1]).removeClass("hidden");
I ended up solving it like this:
var ids = [];
var minlength = [];
var maxlength = [];
var required = [];
for(var item in data) {
//push values into array
ids.push(data[item]['Field']);
maxlength.push(data[ids.length-1]['MaximumLength']);
minlength.push(data[ids.length-1]['MinimumLength']);
required.push(data[ids.length-1]['Options']);
//removes the class hidden and therefor shows the Element
$("." + ids[ids.length-1]).removeClass("hidden");
//adds the Attribute minlength to the html element
$("#" + ids[ids.length-1]).attr('minlength', minlength[minlength.length-1]);
//adds the Attribute maxlengthto the html element
$("#" + ids[ids.length-1]).attr('maxlength', maxlength[maxlength.length-1]);
//if the value in the Array is "Mandatory", adds the Attribute "required" to the html element
if (required[ids.length-1] == "Mandatory") {
$("#" + ids[ids.length-1]).attr('required', "required");
}

AngularJS - dynamically created ngmodel cannot be set from controller

I am working on code where user selects an item from dropdown list and the UI elements are displayed according to that selected item. Example: if item1 is selected there will be 2 textboxes, 1 textarea and a checkbox. item2 will have 1 textbox. etc.
So, I currently have a function where I add html elements according to item selected. I get a JSON file where there is list of items and what UI elements are required for that item. When user selects an item I get the required information from that JSON file and call following code:
$scope.myHTML = "";
var aForm = (angular.element(document.getElementById('appType')));
aForm.html('');
dropdown.forEach(function(viewItem, index){
if(viewItem.control_type === "TextBox"){
$scope.myHTML += '<label class="label">'+ viewItem.label +'</label>'+
'<input type="text" ng-model = "item.value'+index + '" placeholder = "'+ viewItem.text +'">';
}
if(viewItem.control_type === "TextArea"){
$scope.myHTML += '<label class="label">'+ viewItem.label +'</label>'+
'<textarea type="text" rows="4" ng-model = "tests.value'+index + '" ></textarea>'';
}
}
aForm.append($scope.myHTML);
$compile(aForm)($scope);
So the ng-model will have item.value0,item.value1 and so on for each element. I have used $compile to add the html view to UI.
The problem is that I can get the values in my controller but I cannot set those values from controller.
dropdown.forEach(function(viewItem, index){
$scope.tests['value'+index] = "SomePresetValue"; //Does not update value on HTML
});
Does not set value to the HTML element. I tried the following after searching for alternate solutions but did not work.
$scope.$apply(function(){
dropdown.forEach(function(viewItem, index){
$scope.item['value'+index] = viewItem.value;
});
});

how to get the value of dynamically created selectbox

I am creating a div dynamically with ajax. Now if the ajax call is success then i created a string for div element and append it to the original div id.
here is my code
$.ajax({
type:"GET",
url:"resources/json/asnData.json",
dataType:"json",
success:function(data){
$.each(data.Payload, function(index, val){
i=i+1;
stmt+='<div class="row">'+
'<section class="col col-2">'+
'<label class="input"><i class="icon-append fa fa-key"></i>'+
'<input type="text" name="keyName" value="'+val.key+'" readonly/>'+
'</label>'+
'</section>'+
'<section class="col col-3">'+
'<label class="select">'+
'<select id="dataConversionType'+i+'" class="dataConversionType">'+
'<option value="HEX">HEX</option>'+
'<option value="ALL">Compare All</option>'+
'<option value="ASCII">ASCII</option>'+
'<option value="STRING">STRING</option>'+
'<option value="INT">INTEGER</option>'+
'<option value="BINT">BIG INTEGER</option>'+
'</select><i></i>'+
'</label>'+
'</section>'+
'<section class="col col-5">'+
'<label class="input"><i class="icon-append fa fa-dashcube "></i>'+
'<input id="convertedType'+i+'" type="text" value="'+val.value+'" readonly/>'+
'</label>'+
'</section>'+
'</div>';
});
$(".dataParser").append(stmt);
Now there is function where if someone select a value in selectbox then fire and show.
$('#dataConversionType'+i).change(function(e) {
e.preventDefault();
var conversionType=$(this).val(); //I have doubt here also..
console.log(conversionType);
if(conversionType == 'ALL') {
console.log('ALL-Show a modal with each possible conversion');
}
but this is not working. this function works if I called using the class name. But i have to call the function using id with the i value, so that with that i value i can also set some value in other fields.
any help will be appreciated...
Use class instead of id (replace document with some non dynamic container)
$(document).on('change','.dataConversionType',function(e) {
e.preventDefault();
var conversionType=$(this).val();
console.log(conversionType);
var index_val = $(this).attr('data-index')
if(conversionType == 'ALL') {
console.log('ALL-Show a modal with each possible conversion');
}
)};
And when you are generating your element add a data attribute
'<select id="dataConversionType'+i+'" class="dataConversionType" data-index="'+i+'">'
Also if you are inside a loop you need to wrap your ajax within a closure if you want to get correct value and not the latest one.
(function(idx) {
//ajax stuff here
}(i)
Do one thing, Listen to the change event using class name itself, instead of Id.
Put value of i as a custom attribute into the select box. In the listener function, read this attribute and call or perform whatever actions you have to do.
A sample is as below:
'<section class="col col-3">'+
'<label class="select">'+
'<select id="dataConversionType'+i+'" class="dataConversionType" data-count=i>'+
'<option value="HEX">HEX</option>'+
'<option value="ALL">Compare All</option>'+
'<option value="ASCII">ASCII</option>'+
'<option value="STRING">STRING</option>'+
'<option value="INT">INTEGER</option>'+
'<option value="BINT">BIG INTEGER</option>'+
'</select><i></i>'+
'</label>'+
'</section>'
Event listener:-
$('.dataConversionType').change(function(e) {
e.preventDefault();
var conversionType=$(this).val(); //selected value
var valueofI = $(this).attr("data-count");// Value of i
}
data-count is the custom attribute.
Try On change method
$(document).on('change','.dataConversionType',function(e) {
// Paste Your Code
});
OR
$(document).on('change','#dataConversionType',function(e) {
// Paste Your Code
});
$('#dataConversionType1').change(function(e) {alert("Changed")});
this code will not work for dynamically append select box.
you should try-
$(document).on("change","#dataConversionType1",function(){
alert($('#dataConversionType1 option:selected').val());
});
This works for me.
The value of i has been now changed to the latest one and this would not give you all the selectboxes anyways.
If you want to be specific about any select box, do it like:
$('#dataConversionType1').change(function(e) {
// code here
});
If you want to do something on all the selectboxes you have created, you can do it like:
$('[id^="dataConversionType"]').change(function (e) {
// Find the index: Count of i
var elmIndex = $(this).attr("id").replace("dataConversionType", "");
// Reflects the value of it in related input field
$("#convertedType3" + elmIndex).val($(this).val());
});
If you want to use the value of i later for operations, you can do it in 2 ways:
set the value of i in some data- attribute like: data-index=i (example below):
'<select id="dataConversionType'+i+'" class="dataConversionType" data-index="' + i + '">'+
Get the index from the id itself doing split or regex (example: /\d/).

How can I retrieve input values from elements added after page load?

I'm working with Zend Framework 1.12 and I've need to be able to dynamically add and delete fields from a sub-form, in this case we're associating hyperlinks to a parent "promotion".
I haven't found a way to accomplish dynamically adding and removing elements via Zend, and the rare tutorial I've found that claimed to do this are half a decade old and aren't working when I attempt them.
So what I am doing is storing the links I need to work with in a Zend Hidden input field and then dealing with the JSON data after I submit. Not very efficient, but it's the only thing I've gotten to work so far.
Below is the section of the code I'm working with:
Assume a form like:
<form action="/promos/edit/promo_id/15" method="POST" id="form_edit">
<!-- input is Zend_Form_Element_Hidden -->
<input type="hidden" id="link_array" value="{ contains the JSON string }"/>
<button id="add_link">Add Link</button>
</form>
The purpose is that every time the Add Link button is pressed, the form adds fields to allow the user to input new hyperlinks that will be associated with the specific items.
Here's the function:
// add links
$('#add_link').click(
function(e) {
e.preventDefault();
link = '<div class="p_link new_link">' +
'<div class="element_wrap">' +
'<label for="link_name" class="form_label optional">Text: </label>' +
'<input type="text" id="new_link_name" name="link_name"/>' +
'</div>' +
'<div class="element_wrap">' +
'<label for="link_http" class="form_label optional">http://</label>' +
'<input type="text" id="new_link_http" name="link_http"/>' +
'</div>' +
'<div class="element_wrap">' +
'<button class="submit delete_link">Delete</button>' +
'</div>' +
'</div>';
$('#add_link').prev().after(link);
}
);
Now, what I need to do is on submit, for every new_link class element, to take the links name and http reference and place it in a json object. Here's the code as I have it so far (I know I don't have both input fields represented at this point):
$('#submit').click(
function(e) {
e.preventDefault();
var link_array = [];
var new_links = document.getElementsByClassName('new_link');
$.each(new_links, function() {
console.log(this);
var n = $(this).children('#new_link_name').text();
console.log(n);
link_array.push({'link_name':n}); //'link_http':h
});
console.log(JSON.stringify(link_array));
}
);
My problem is that: var new_links = document.getElementsByClassName('new_link'); will collect all the newly added new_link elements, but it does not pull in any value that has been input into the text fields.
I need to know how I can apparently bind any input I make to the input field's value attribute, because right now anything I type into these new elements are tossed out and the field appears empty when it's anything but.
$('#submit').click(
function(e) {
e.preventDefault();
var link_array = [];
var new_links = $('.new_link');
$.each(new_links, function() {
console.log(this);
var n = $(this).find('input').val(); // you need input values! This line //is changed...
console.log(n);
link_array.push({'link_name':n}); //'link_http':h
});
console.log(JSON.stringify(link_array));
}
);
JSFIDDLE: http://jsfiddle.net/DZuLJ/
EDit: You can't have multiple IDS (make class for each input, and target class, if you want link names and http's)

How can I create dynamic controls and put their data into an object?

I created a div and a button. when the button clicked, there will be a group of element(included 1 select box and 2 text inputs) inserted into the div. User can add as many group as they can, when they finished type in data of all the group they added, he can hit save button, which will take the value from each group one by one into the JSON object array. But I am stuck in the part how to get the value from each group, so please help, thank you.
The code for the div and the add group button function -- AddExtra() are listed below:
<div id="roomextra">
</div>
function AddExtra() {
$('#roomextra').append('<div class=extra>' +
'<select id="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" id="insetLength">' +
'Width(m): <input type="text" id="insetWidth">' +
'Height(m): <input type="text" id="insetHeight">' +
'</div>');
}
function GetInsetOffSetArray (callBack) {
var roomIFSDetail = [{
"IsInset": '' ,
"Length": '' ,
"Width": '' ,
"Height": ''
}];
//should get all the value from each group element and write into the array.
callBack(roomIFSDetail);
}
This should just about do it. However, if you're dynamically creating these groups, you'll need to use something other than id. You may want to add a class to them or a data-* attribute. I used a class, in this case. Add those classes to your controls so we know which is which.
var roomIFSDetail = [];
var obj;
// grab all of the divs (groups) and look for my controls in them
$(.extra).each(function(){
// create object out of select and inputs values
// the 'this' in the selector is the context. It basically says to use the object
// from the .each loop to search in.
obj = {
IsInset: $('.isInset', this).find(':selected').val() ,
Length: $('.insetLength', this).val() ,
Width: $('.insetWidth', this).val() ,
Height: $('.insetHeight', this).val()
};
// add object to array of objects
roomIFSDetail.push(obj);
});
you'd better not to use id attribute to identity the select and input, name attribute instead. for example
$('#roomextra').append('<div class=extra>' +
'<select name="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" name="insetLength">' +
'Width(m): <input type="text" name="insetWidth">' +
'Height(m): <input type="text" name="insetHeight">' +
'</div>');
}
and then, usr foreach to iterate
$(".extra").each(function() {
var $this = $(this);
var isInset = $this.find("select[name='isInset']").val();
var insetLength = $this.find("input[name='insetLength']").val();
// ... and go on
});
A common problem. A couple things:
You can't use IDs in the section you're going to be repeating, because IDs in the DOM are supposed to be unique.
I prefer to use markup where I'm writing a lot of it, and modify it in code rather than generate it there.
http://jsfiddle.net/b9chris/PZ8sf/
HTML:
<div id=form>
... non-repeating elements go here...
<div id=roomextra>
<div class=extra>
<select name=isInset>
<option>Inset</option>
<option>OffSet</option>
</select>
Length(m): <input id=insetLength>
Width(m): <input id=insetWidth>
Height(m): <input id=insetHeight>
</div>
</div>
</div>
JS:
(function() {
// Get the template
var container = $('#roomextra');
var T = $('div.extra', container);
$('#addGroup').click(function() {
container.append(T.clone());
});
$('#submit').click(function() {
var d = {};
// Fill d with data from the rest of the form
d.groups = $.map($('div.extra', container), function(tag) {
var g = {};
$.each(['isInset', 'insetLength', 'insetWidth', 'insetHeight'], function(i, name) {
g[name] = $('[name=' + name + ']', tag).val();
});
return g;
});
// Inspect the data to ensure it's what you wanted
debugger;
});
})();
So the template that keeps repeating is written in plain old HTML rather than a bunch of JS strings appended to each other. Using name attributes instead of ids keeps with the way these elements typically work without violating any DOM constraints.
You might notice I didn't quote my attributes, took the value attributes out of the options, and took the type attributes out of the inputs, to keep the code a bit DRYer. HTML5 specs don't require quoting your attributes, the option tag's value is whatever the text is if you don't specify a value attribute explicitly, and input tags default to type=text if none is specified, all of which adds up to a quicker read and slimmer HTML.
Use $(".extra").each(function() {
//Pull info out of ctrls here
});
That will iterate through all of your extra divs and allow you to add all values to an array.

Categories

Resources