Dynamically duplicated forms disappear on CodeIgniter reload - javascript

I have the following code that needs to be duplicated:
<form method="post">
<div id="field-row-container">
<div id="field-row-1" class="field-row">
<div class="field-element">
<label for="Name[1]">Name</label>
<input type="text" id="Name[1]" name="Name[]" />
</div>
<div class="field-element">
<label for="Email[1]">Email</label>
<input type="text" id="Email[1]" name="Email[]" />
</div>
<hr/>
</div>
</div>
<div class="form-element">
<input type="button" class="confirm add-field-row" value="Add" />
<input type="button" class="danger delete-field-row" value="Delete" />
<input type="submit" />
</div>
The duplicated / dynamically added elements will have the same names of Name[] and Email[] but their ID's will be incremented.
The JavaScript is below, based from Josiah Ruddell's form duplication script.
var template = $('#field-row-container #field-row-1').clone();
window.addForm = function () {
var parent = $(this).closest('.dynamic-rows').attr('id');
var fieldRowCount = countRows(parent) + 1;
var newFieldRow = template.clone().find(':input').each(function () {
var newId = this.id.substring(0, this.id.length - 3) + "[" + fieldRowCount + "]";
$(this).prev().attr('for', newId); // update label for
this.id = newId; // update id and name (assume the same)
$(this).closest('.field-row').addClass('new-row');
}).end()
.attr('id', 'field-row-' + fieldRowCount)
.appendTo('#field-row-container');
}
$('.add-field-row').click(addForm);
Whenever I submit the form to CodeIgniter and if there is a validation error, once the controller reloads the multi-part form, the dynamically added elements disappear as well as the values in the initial fields.
How do I go around this problem? I'm at a loss on how to solve this...
Other notes that might help:
This is a component multi-part form with only one form controller
I have multiple instances of this - Addresses, Education Degrees and such
I use CodeIgniter's form_validation library to check server-side each array of posts

When the page with the form on reloads after the controllers redirects back to it after failing validation, it will only reload the original page, with no DOM manipulations applied.
I would perform the POST request which submits the form via ajax, so you can handle the response without leaving the page. Something like this:
$.post('/locationOfController.php', $('#yourForm').serialize(), function(response){
if(response.valid){
window.location.href = '/somewhereAfterFormPosted.php';
} else {
$('#yourForm').append("<p>"+response.error+"</p>");
}
}, 'json');
and change the controller to return a JSON object based on whether validation passed or not. To match up with my example above, you would return something like below when an error occurs:
{valid: false, error: 'Please fill out the whole form'}
Try something like that as a basic example. You could do much more, such as returning several errors if multiple fields are invalid.

Related

Passing form attributes into partials

I am working on an app with NodeJS and have been able to use handlebars and partials without much trouble. I am getting to the point where I have view and edit forms for a car.
For example, after the user submits an application I have "View" and "Edit" links that go to localhost:3000/cars/:id/view and localhost:3000/cars/:id/edit, respectively.
The only difference between these two links is that the "View" page has the form with readonly="readonly" and the "Edit" does not have the readonly attribute.
What I would like to do
cars/view
{{ >car_form readonly=true }}
cars/edit
{{ >car_form readonly=false }}
<button type="submit">Submit</button>
Is this possible with handlebars templates? Or is there something similar I can do to get the result I want?
Thank you!
You're passing in the readonly option correctly, now all you need to do is use it when rendering your form.
To do that I've used a helper to render the form via JavaScript, where we can do anything we like using the Hash Arguments funtionality Handlebars supports.
// Let's pretend this is the user input you're holding in Node.js
// and want to render in your view and edit forms.
var userInput = {
"name": "Bob",
"tagline": "Yep, I'm Bob!"
};
Handlebars.registerHelper('userForm', function(options) {
var formOpening = options.hash.readonly ? "<form readonly=\"readonly\">" : "<form>";
// Notice that I feed in `userInput` as the context here.
// You may need to do this differently, depending on your setup.
var formContents = options.fn(userInput);
return formOpening + formContents + "</form>";
});
var userFormTemplate = Handlebars.compile(document.getElementById("userForm-template").innerHTML);
var pageTemplate = Handlebars.compile(document.getElementById("page-template").innerHTML);
Handlebars.registerPartial('userForm', userFormTemplate);
document.getElementById("wrap").innerHTML = pageTemplate();
<div id="wrap"></div>
<script id="page-template" type="text/x-handlebars-template">
<h2>View</h2>
{{> userForm readonly=true}}
<h2>Edit</h2>
{{> userForm readonly=false}}
</script>
<script id="userForm-template" type="text/x-handlebars-template">
{{#userForm readonly=readonly}}
<input type="text" name="name" value="{{name}}" />
<input type="text" name="tagline" value="{{tagline}}" />
<button type="submit">Submit</button>
{{/userForm}}
</script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v4.0.5.js"></script>
In the above snippet, the readonly="readonly" attribute is being added to the form beneath the "View" heading.
Note that on my browser, this does not actually make the form read-only - I'm not sure if you've got another library or something to handle that?

AJAX Form, passing return message

I have my AJAX form it works great.
Every time I submit the form It returns the result inside the <div id="message"></div>, but it gets complicated when I have multiple forms. So I was wondering if their is a way to indicate inside the form what <div> to return the message to.
Here is my AJAX.js
$("form#ajaxForm").on("submit", function() {
var form = $(this),
url = form.attr("action"),
type = form.attr("method");
data = {};
form.find("[name]").each(function(index, value){
var input = $(this),
name = input.attr("name"),
value = input.val();
data[name] = value;
});
$.ajax({
url: url,
type: type,
data: data,
success: function(response) {
$("#message").html(response); //I would like to interactively switch the return div, from #message to like #message2
$("body, html").animate({
scrollTop: $( $("#message") ).offset().top - 5000
}, 600);
}
});
return false;
});
In the form I would like to indicate where the return div is, like
<form action="../forms/add_event_form.php" method="post" id="ajaxForm">
//Can I add an input somewhere here? To indicate where I want the return to go too? Like <input type="hidden" value="message2" name="return">
<input type="text" class="formI" name="date" id="dateI" placeholder="Date">
<input type="submit" name="submit" class="btn btn-primary" value="Add">
</form>
Thank you for reading this. Have a good day! And Thank you in advance for your responses.
Yes, it will not work automatically, but you can add some information to the form and then use it to decide where to put returned HTML. Doing that with additional inputs may not be the best way though, as it can be achieved with far less impact on the DOM: with an attribute on the form itself.
Here's an example of how you may do that.
$(".ajaxForm").on("submit", function(e) {
e.preventDefault();
var form = $(this);
// using jQuery's `data()` to get an ID of response element from the 'data-response' attribute
var responseElementId = form.data("response");
var response = $(responseElementId);
response.html(produceResponse(form));
// function that produces some html response
// you'll use AJAX request to the server for that
// so don't mind its complexity or bugs
function produceResponse(form) {
var data = form.find("input").map(function(i, el) {
return "'" + el.name + "': " + el.value;
});
return "<p>You've submitted:\n<pre>" + Array.prototype.join.call(data, ",\n") + "</pre></p>";
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Form #1</h2>
<form action="#" class="ajaxForm" data-response="#response1">
<input name="first-name" type="text">
<button>Submit</button>
</form>
<div id="response1"></div>
<h2>Form #2</h2>
<form action="#" class="ajaxForm" data-response="#response2">
<input name="last-name" type="text">
<button>Submit</button>
</form>
<div id="response2"></div>
Here I use a data attribute because it was designed for cases like this: to store arbitrary data related to the element, but which doesn't have any defined meaning for the browser. Accessing data stored in such way is really convenient with its HTML5 API, but because of pretty low support from IE (it has it only starting from the version 11), one may use jQuery's method data() to do the same.

How to get formData from Angular-Payments

I am using Angular-Payments that intercepts the form data and submits it to Stripe. This works well, however, I'm not sure how to access form data after its sent to stripe. For example, my form has quantity field which I would like to get access to but I don't know how to...
Here is what I'm doing HTML
<form stripe-form="handleStripe" role="form" ng-if="authenticated" name="takeMoneyForm" ng-submit="takeMoney(takeMoneyForm, model)">
<input type="text" name="card_number" ng-model="number" payments-validate="card" payments-format="card" payments-type-model="type" ng-class="takeMoneyForm.number.$card.type">
<input type="text" name="card_cvc" ng-model="cvc" payments-validate="cvc" payments-format="cvc" payments-type-model="type">
<input type="text" nam="card_expiry" ng-model="expiry" payments-validate="expiry" payments-format="expiry">
<input type="text" ng-model="quantity"/>
<button class='form-control submit-button btn btn-majoo' type='submit'>Pay ยป</button>
</form>
JS
$scope.takeMoney = function(formData, model){
$scope.handleStripe = function(status, response){
if(response.error) {
// there was an error. Fix it.
alert("Error happened")
} else {
var dataModel = {
email: model.email,
profile: {
stripe_token: response.id,
stripe_id: model.profile.stripe_id
//here I would like to get access to the quantity from the form
}
}
djangoAuth.takeMoney(dataModel)
$scope.complete = true;
}
}
}
I feel like this should be simple but I'm very new to Angular and can't seem to figure this out.
since youre using ng-model the values of those fields should be on that form's scope(as in scope.number)
If they are not accessible it could be one of two things:
1) Angular Payments clears the ng-model following submit
2) you are trying to access it from a different scope.

Parsley.js - Radiobuttons with same name in different forms on same page are validated together

I have searched for almost 2 days now, but can't seem to find an answer to this problem.
On one page I have two different forms (registration, guest checkout). Both use almost the same form elements which then have same name attributes. On submitting, only the current form gets validated and everything works fine for e.g. text input fields.
BUT: Radiobuttons and checkboxes are treated differently by Parsley.js - so on submitting the guest checkout form (which is second in markup) the error messages and classes are added to the registration form. This really only is the case with those two input types.
It seems that Parsley doesn't make a difference to which form those elements belong. It just looks at the name attribute. This is somewhat annoying, especially as there are no problems with other input types sharing same name attributes.
Here is a code snippet for the HTML:
<form id="registrationForm" data-validate-form="true" ...>
<label>Mrs</label>
<input type="radio" name="salutation" value="mrs"/>
<label>Mr</label>
<input type="radio" name="salutation" value="mr" data-validate-required="true"/>
<label>Firstname</label>
<input type="text" name="firstname" data-validate-required="true"/>
</form>
<form id="guestcheckout" data-validate-form="true" ...>
<label>Mrs</label>
<input type="radio" name="salutation" value="mrs"/>
<label>Mr</label>
<input type="radio" name="salutation" value="mr" data-validate-required="true"/>
<label>Firstname</label>
<input type="text" name="firstname" data-validate-required="true"/>
</form>
And here the JavaScript settings:
$('[data-validate-form]').parsley({
namespace : 'data-validate-',
errorsWrapper : '<div></div>',
errorTemplate : '<span></span>',
errorClass : 'error',
successClass : 'success'
});
Has anybody else ever encountered this problem? Oh, and I am not able to change the name attributes.
Thanks in advance for your help!
So, my colleague and I found a solution for this.
In the handleMultiple method we defined the element's current form and added its ID to the multiple string:
// Add current form id to name to differ between several forms on same page.
var currentForm = $('#' + this.$element[0].form.id);
multiple = currentForm.attr('id') + '-' + multiple;
Then we added currentForm to the input selector like so:
$('input[name="' + name + '"]', currentForm).each(function () {...}
This ensures that only the inputs in the correct form are selected.
Then move to the setupField method. In the definition for _ui.errorsWrapperId we also added the ID of the current form (fieldInstance.$element[0].form.id).
Original:
_ui.errorsWrapperId = 'parsley-id-' + ('undefined' !== typeof fieldInstance.options.multiple ? 'multiple-' + fieldInstance.options.multiple : fieldInstance.__id__);
New:
_ui.errorsWrapperId = 'parsley-id-' + ('undefined' !== typeof fieldInstance.options.multiple ? 'multiple-' + fieldInstance.$element[0].form.id + '-' + fieldInstance.options.multiple : fieldInstance.__id__);
This is necessary to print the error message correctly.
Maybe this helps somebody else, too.

jQuery: How to submit an array in a form

I have the following form. Each time the users clicks add_accommodation I want to add to an array that I will return to the end point (http://server/end/point).
<form action="http://localhost:3000/a/b/c" method="post">
<div>
<input type="hidden" id="Accommodation" name="accommodation"><div>
</div>
</form>
<div id="accommodation_component">
<div>
<label for="AccommodationType">Type:</label>
<input type="number" step="1" id="accommodationType" name="accommodation_type" value="0">
</div>
<div>
<button type="button" id="add_accommodation">Add Accommodation</button>
</div>
</div>
<script>
$( document ).ready(function() {
$('#add_accommodation').click(function() {
make_accommodation(this);
});
});
function make_accommodation(input) {
var value = {
type : $("#AccommodationType").val(),
};
var accommodation = $('#Accommodation').attr('id', 'accommodation');
accommodation.push(value);
console.log(accommodation);
}
</script>
At my end point I want the result to be and array (accommodation = [{1},{2},{3},{4}]). How can I do this?
Give the form an id, and just append a new hidden(?) input that has a name that has [] at the end of it, it will send the values as an array to the server.
HTML
<form id="myform" ...>
Javascript
function make_accommodation(){
var newInput = $("<input>",{
type:"hidden",
name:"accommodation[]",
value: {
type: $("#AccommodationType").val()
}
});
$("#myform").append(newInput);
}
Also you list the output as [1,2,3,4] but your code shows you setting the value as an object with a property type and setting it to the value of the accommodation input, i am going to assume that was a mistake. If I am mistaken just modify the value property in the code above.
Also in your code you change the id of the input, not sure why you were doing that as it serves no purpose and would have made your code error out so i removed it.
EDIT
Since you are wanting to send an array of objects, you will have to JSON.stringify the array on the client end and decode it on the server end. In this one you do not need multiple inputs, but a single one to contain the stringified data.
var accommodationData = [];
function make_accommodation(){
accommodationData.push({
type: $("#AccommodationType").val()
});
$("#accommodation").val( JSON.stringify(accommodationData) );
}
Then on the server you have to decode, not sure what server language you are using so i am showing example in PHP
$data = json_decode( $_POST['accommodation'] );
If you are using jQuery's ajax method you could simplify this by sending the array data
jQuery.ajax({
url:"yourURLhere",
type:"post"
data:{
accomodation:accommodationData
},
success:function(response){
//whatever here
}
});
Add antorher hidden field in form
<input type="hidden" name="accommodation[]"> // click1
<input type="hidden" name="accommodation[]"> // click2
...
<input type="hidden" name="accommodation[]"> // clickn
Then when you submit form on server you will have array of accommodation.
JS part :
function make_accommodation() {
$(document.createElement('input'))
.attr('type', 'hidden')
.attr('name', 'accommodation[]')
.val($("#AccommodationType").val())
.appendTo('form');
}
on server(PHP) :
print_r($_POST['accommodation']);
Since you're using jQuery you can create a function which creates another hidden field, after clicking on the button
<div id='acommodation-wrapper'></div>
<button type="button" id="add_accommodation" onclick="addAnother()">Add Accommodation</button>
<script type="text/javascript">
function addAnother(){
var accWrapper = $('#accommodation-wrapper');
var count = accWrapper.children().length;
var div = "<input type=\"hidden\" class=\"accommodation-"+count+"\" name=\"accommodation["+count+"]\"></div>";
accWrapper.append(div);
}
</script>

Categories

Resources