Best way to add a dynamic amount of elements to a form? - ajax

I have a complex form that has a static section and one that can have from 0 to many divs that containing radio buttons, textfields and textareas.
I'm wondering what's the best way to add elements to the section that has a variable amount of form inputs. I have a working solution, but it's probably not the best:
I use javascript to add a chunk of html code and append it to the div containing the variable amount of input fields. In the code sample below, my javascript code would do something like
Javascript
document.getElementId('dynamic_form_stuff').innerHTML += "<div id='element3'>Form stuff</div>";
HTML
<form>
<div id="static_form_stuff">
form fields
</div>
<div id="dynamic_form_stuff">
<div id="element1">
Radio buttons stuff
Text field stuff
Text area stuff
</div>
<div id="element2">
Radio buttons stuff
Text field stuff
Text area stuff
</div>
</div>
</form>

I think this largely depends on what you are doing elsewhere, and how many items you are adding, as well as how you want to add event handlers.
I tend to find it easier to use the DOM methods if I need to add event handlers, but if you are just adding to a form with a submit button, then using innerHTML is faster, as shown here: http://www.quirksmode.org/dom/innerhtml.html.

I would personally do something like:
var elem = document.getElementId('dynamic_form_stuff');
var div = document.createElement('div'); // create element
div.setAttribute('class', 'myclass'); // define attributes
elem.appendChild(div);
// and/or more code.....
This gives me more control in adding attributes and style there.

Related

Bootstrap Dynamic Modals With AJAX Calling

I'm using codeigniter v3 and bootstrap v3.
I've a table for messages and for every message in table, when click on details button, a bootstrap modal show the details.
In a for loop, I print table rows and for every row (at end of the loop), I put whole bootstrap modal structure.
My question is: how could do this with ajax calling? I mean, I don't put all modal code for every table row (every message) and every time that details button clicked, I handle showing modal with ajax.
thanks for attention.
SOLVED:
I find an easy and I think better way in the bootstrap official website: Using data- attribute.
I show it with an working example for who that could not achieve better solution:
Suppose we want to fill a table body with some data (as my problem):
//just table body code
<tbody>
<?php foreach($fields as $field): ?>
<tr>
<td><?php $field->some_field; ?></td>
//other <td> elements
<td>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal"
data-time="<?php echo $field->time; ?>">Show Details</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
So in a loop, I read data (that in controller, get with model's method, and pass to view with $data['fields']). Now for showing some details in modal, I use HTML5 data attribute. Suppose, I want to show time in the modal. As you see in above code, I put time field in data-time:
data-time="<?php echo $field->time; ?>"
Now I create a modal as template (you could see whole modal structure in bootstrap official website) and put it out of loop (one modal for all table rows; dynamic data). in the following code, I put an element in the modal body (as a placeholder):
//... in the modal body section
<h4 id="time"></h4>
This element have no content, because I want to retrieve every row time filed and put it in this element. Note this will be practical with defining an id. Now some script:
//first load jquery
<script type="text/javascript">
$(document).ready(function(){
$('#myModal').on('show.bs.modal', function(event){
var btn = $(event.relatedTarget); // find which button is clicked
var time = btn.data('time'); //get the time data attribute
$('#time').text(time); //put the data value in the element which set in the modal with an id
});
});
</script>
You could define more data attribute and retrieve in this way.
I will not write the code for you, but show you the way:
You just need one modal for the whole page and it works like a template.
You need same data/informations to be displayed in the modal. This data you can pick up via Javascript/jQuery from your HTML. I prefer data attributes for that. Something like:
data-modal-title="My Title" data-modal-content="My Content"
Now you inject this data in your modal template and open the modal via Javascript.

How to clear selected value from Bootstrap FormHelpers SelectBox

How does one access the various options for the bootstrap formhelpers library?
I have tried every way of accessing them, but get an error every time.
Specifically, I'm trying to clear out the selected value in a bfh-selectbox
$("#Select").val('');
$("#Select").selectpicker("refresh");
see How to reset value of Bootstrap-select after button click
Its hard to clear the value of a select box since its a dropdown. Do you mean setting the dropdown to a specific option?
For your specic question: You can set and get the value of the bfh-selectbox with JQuery like this:
HTML:
<div id="selBox" class="bfh-selectbox" data-name="selectbox1">
<div data-value="1">Option 1</div>
<div data-value="2">Option 2</div>
<div data-value="3">Option 3</div>
</div>
Get value:
var output = $("#selBox").val();
Set value:
$("#selBox").val([Replace with valid option value]);
BFH are great components, but their documentation is really lacking.

prototype : onclick remove previous element

i have html as below in which onclick of <a> i want to remove the text box above it.
<input class="sku-box" class="input-text validate-number" type="text" title="file-number" name="sku[]">
<a value="remove" onclick="remove()" href="javascript:void(0);">remove</a>
<input class="sku-box" class="input-text validate-number" type="text" title="file-number" name="sku[]">
<a value="remove" onclick="remove()" href="javascript:void(0);">remove</a>
my solution to this, i changed the <a> tag to this.
remove
and my prototype function look like this
function removefield(ele)
{
$(ele).previous().remove();
ele.remove();
}
You have several options for observing click events, and usually I wire up click events after the dom is loaded using something like:
document.on('click', 'a', myFunction.BindAsEventListener())
The above statement sets you up for observing all click events occurring for the a element firing up the function myFunction. Once you have this established you can then either trap the event or simply allow it to bubble up or do both, trap and bubble up the event.
However, with the direction you are going there you would be better off to pass the identity of your a tag to the remove function, then it is easy to remove the previous element. So you would have:
<a id="a_tag1" value="remove" onclick="remove('a_tag1')" href="javascript:void(0);">remove</a>
Then your function remove might look something like this:
function remove(a) {
// prev element
var elm = $(a).previous('input');
// remove it
if(elm)
elm.remove();
}
This is very basic and in reality you would need to do things to guarantee that the previous input element you are grabbing is associated with the a element you clicked. You could do this by agreeing on a new data-xxxx element tag or an arbitrary class name you can use to compare the elements. For example, your a tag might look like:
<a data-group='monkeys'>...</a>
And the cooresponding input tag might look like:
<input data-group='monkeys'>...</input>
Then, in the above code where you call previous on the a tag, you would construct your select to include a test on the data-group value that matches the current a tag.
Karl..

Separating template logic from Backbone.View

I just started learning Backbone.js, and have been working on (what else) a simple to-do application. In this app, I want to display my to-do items inside of <ul id="unfinished-taks"></ul> with each task as a <li> element. So far, so simple.
According to the tutorials I have read, I should create a View with the following:
// todo.js
window.TodoView = Backbone.View.extend({
tagName: 'li',
className: 'task',
// etc...
});
This works fine, but it seems like bad practice to define the HTML markup structure of my to-do item inside of my Javascript code. I'd much rather define the markup entirely in a template:
// todo.js
window.TodoView = Backbone.View.extend({
template: _.template($("#template-task").html()),
// etc...
});
<!-- todo.html -->
<script type="text/template" id="template-task">
<li class="task <%= done ? 'done' : 'notdone' %>"><%= text %></li>
</script>
However, if I do it that way Backbone.js defaults to using tagName: 'div' and wraps all my to-do items in useless <div> tags. Is there a way to have the HTMl markup entirely contained within my template without adding unsemantic <div> tags around every view element?
If you are only planning to render the view once, you can set the el property of the view manually in .initialize():
// todo.js
window.TodoView = Backbone.View.extend({
template: _.template($("#template-task").html()),
initialize: function() {
this.el = $(this.template(this.model.toJSON())).get(0);
},
// etc
});
There are some caveats here, though:
Backbone expects the el property to be a single element. I'm not sure what will happen if your template has multiple elements at the root, but it probably won't be what you expect.
Re-rendering is difficult here, because re-rendering the template gives you a whole new DOM element, and you can't use $(this.el).html() to update the existing element. So you have to somehow stick the new element into the spot of the old element, which isn't easy, and probably involves logic you don't want in .render().
These aren't necessarily show-stoppers if your .render() function doesn't need to use the template again (e.g. maybe you change the class and the text manually, with jQuery), or if you don't need to re-render. But it's going to be a pain if you're expecting to use Backbone's standard "re-render the template" approach for updating the view when the model changes.

How to serialize a form with dynamically added inputs using jQuery?

I've read through a lot of questions addressing similar question but I can't get a grip on it, yet.
I have a simple HTML form just like
<form id="edit-items" name="edit-items" onsubmit="saveItems();">
<input type="submit" value="Save">
<input class="item" id="ei81" type="hidden" name="i[81]" value="1">
<input class="item" id="ei124" type="hidden" name="i[124]" value="1">
</form>
The two existing hidden inputs could be set upon document loading due to a prior save.
Now I have images (kind of a menu). If they are clicked a corresponding hidden input is appended to the form:
<img id="i37" class="clickable-item" src="items/i37.gif" title="item name" onclick="addItem(37,1)" />
The addItem function:
function addItem(id,n) {
var zitem = $("#e"+id);
if ( 0 in zitem ) {
if ( zitem.val() > 0 ) {
var newcnt = parseInt(zitem.val()) + n;
if ( newcnt <= 0 ) {
zitem.remove();
}
else {
zitem.val(newcnt);
}
}
}
else if(n == 1) {
var iform = $("#edit-items");
iform.append("<input class=\"item\" id=\"e"+id+"\" type=\"hidden\" name=\"i["+id+"]\" value=\"1\">");
}
}
This part all works correct, after clicking the image, my form looks like
<form id="edit-items" name="edit-items" onsubmit="saveItems();">
<input type="submit" value="Save">
<input class="item" id="ei81" type="hidden" name="i[81]" value="1">
<input class="item" id="ei124" type="hidden" name="i[124]" value="1">
<input class="item" id="ei37" type="hidden" name="i[37]" value="1">
</form>
which is exactly what I want. But then when hitting the submit button only the first two elements are submitted (the ones which have not been added dynamically).
Now, I read a lot about .bind and .live handlers but I am missing some point obviously. I tried to delete the onclick attribute on the images and to bind the .live to them since they are causing the new inputs:
$(".clickable-item").live("click", function() {
addItem($(this).attr("id"),1);
});
However, the ID is not transferred which is needed, though (hence no correct input is added). I learned that .live doesn't bind the handler to any elements but to the event.
Is it even possible to pass the element which has been clicked to the live handler?
Should the images even be watched by .live or should it be bound to something else?
The last thing I learned form another question here is that the inputs should be watched by .live, since they are dynamically added. But what kind of event I would attach? The inputs themselves are not clicked.
I would really appreciate any help as I am cracking my head and starting to get lost on that one.
Thanks in advance,
Paul
Regarding live() [docs]: this refers to the clicked element, so you can pass it to addItem with addItem(this, 1). This part of your code should work.
If you don't add or remove images dynamically then there is no reason to use live. You can just use click() [docs] (and yes, don't use onclick in the HTML).
But I see another problem:
The image id is i37. $(this).attr("id") will return this value.
In your addItem function you then take this value and perform string concatenation. The result will be $("#ii37") (note the two is).
The input element you create will have the id ii37 and not i37.
If you correct this to match it with the other elements like in your example (i.e. i37) , you will have problems because you have several elements with the same id (the input element and the image). If the image comes before the input field in the hierarchy, then $("#i37") will always select the image and you cannot call .val() on an image.
As I don't know what is the overall purpose of the code and what you want to do, I cannot give any suggestion how to improve this. Maybe it is enough to just change the prefix of the image and input field ids.
I learned that .live doesn't bind the handler to any elements but to the event.
That is not correct. .live() binds the event handler to the document root. Events, if not cancelled, bubble up the DOM tree, so they reach the root eventually. There, the event.target [docs] property is examined to determine the element that was clicked.

Resources