I have a problem browsing elements of my forms and posting them as "JSON". I manage to recover everything except some elements like the names of people for example, which are dynamic.
I actually choose a number of names to give, and I would like to get what I have in my array of name.
here is my code :
<script>
parseInt($('#id').html());
console.log(parseInt($('#id').html()));
var handler = StripeCheckout.configure({
key: 'pk_test_nWBzhwnk9WLgDk5EHjr3JTuZ',
image: 'http://localhost:8000/images/default.png',
color: 'white',
locale: 'auto',
token: function(token) {
// You can access the token ID with `token.id`.
// Get the token ID to your server-side code for use.
var myData = {
token: token.id,
email: token.email,
amount: Math.round($("#result").text()),
description: '',
currency: 'eur',
event: parseInt($('#id').html()),
nb_tickets : $('#nb_ticket').text(),
name: [],
};
/*
Make an AJAX post request using JQuery,
change the first parameter to your charge script
*/
$('body').Wload({text:'Paiement en cours'});
console.log(myData);
$.post("/checkout/"+parseInt($('#id').html()), myData,
function(data) {
// if you get some results back update results
$("#myForm").hide();
// for demonstration purposes, loop through everything in myData
})
.done(function () {
$('#element_to_pop_up').bPopup({
modalClose: false,
});
$('body').Wload('hide', {time: 0});
})
.fail(function() {
// if things fail, tell us
$(".results").html("I'm sorry something went wrong");
})
}
});
depending on the number of tickets I choose I can have several names.
in my form the ID of the names is as follows if I choose 2 tickets:
<input type="text" id="commande_achats_0_name" name="commande[achats][0][name]" required="required" class="form-control" placeholder="Name">
and :
<input type="text" id="commande_achats_1_name" name="commande[achats][1][name]" required="required" class="form-control" placeholder="Name">
I need to recover everything in commande_achats_0_name and commande_achats_1_name according to the number of tickets chosen..
I'm stuck on it .. if anyone could help me please
Thank you
Related
I am using sails.js 1.0 with vue.js and want to create a dynamic form that contains a dynamic amount of inputs based on the user's preference. So the user should be able to add another input, type in the data and send the complete form with the dynamic amount of data.
My form looks like this:
<ajax-form action="addStuff" :syncing.sync="syncing" :cloud-error.sync="cloudError" #submitted="submittedForm()" :handle-parsing="handleParsingForm">
...
<input class="form-control" id="input1" name="input1" type="text" :class="[formErrors.password ? 'is-invalid' : '']"
v-model.trim="formData.input1" placeholder="Input #1" autofocus>
...
<ajax-button type="submit" :syncing="syncing" class="btn btn-dark">Save changes</ajax-button>
</ajax-form>
The action addStuff in sails looks like this:
module.exports = {
friendlyName: 'Do some stuff',
description: 'Do some stuff with the form data.',
inputs: {
input1: {
description: 'The first input.',
required: true
}
},
fn: async function (inputs, exits) {
// Do some stuff with the inputs
return exits.success();
}
};
I know that normally I would be able to create a dynamic form using vue.js by
setting the data of the Vue instance to an array
creating a two-way-binding
implementing a v-for loop in the form, that then creates an input for every element in the data object
modifying this array by inserting a new element in the array every time the user wants to add another input.
But with sails and this ajax-form, I do not know how to access the vue instance and the data element of it and how to make this also dynamic in the action. Obviously the input would need to contain an array.
How would it be possible to achieve such a dynamic form?
I figured out the missing part. Sails.js is using parasails which is built on top of vue.js.
When generating a new sails page using the sails generator sails new test-project, there is also a contact form generated which also contains the necessary code which can be adapted for this purpose.
That contact form basically consists of
The .ejs page (=the html code that renders the form) in views/pages
The contact.page.js client-side script in assets/js/pages
The server side controller deliver-contact-form-message.js in api/controllers
In the client-side script, the initial formData can be set:
parasails.registerPage('maindivid', {
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: {
// Main syncing/loading state for this page.
syncing: false,
// Form data
formData: { /* … */ },
// For tracking client-side validation errors in our form.
// > Has property set to `true` for each invalid property in `formData`.
formErrors: { /* … */ },
// Server error state for the form
cloudError: '',
// Success state when form has been submitted
cloudSuccess: false,
},
...
as well as methods etc.
It follows a similar structure than plain vue.js.
To achieve what I was trying to do I added a field as array to the formData
formData: {
myinputs: [
{
key: '',
value: ''
}
]
},
Then I bound that in the .ejs file:
<div class="form-row" v-for="(filter, index) in formData.mypinputs">
<input class="form-control form-control-sm" type="text" :class="[formErrors.password ? 'is-invalid' : '']"
v-model.trim="formData.myinputs[index].key" placeholder="My field">
<button type="button" class="btn btn-secondary btn-sm" #click="addFilterForm">add field</button>
</div>
And finally added a method to the client-side script in contact.page.js (or your name) that gets called when the user clicks the "add field" button.
methods: {
addFilterForm: function() {
this.formData.myinputs.push({
key: '',
value: ''
});
},
Because of the two way binding, as soon as an element is added to the array formData.myinputs, another input is created and added to the DOM.
Sorry if this was answered elsewhere, I tried to search but I'm not even sure what I'm looking for.
Let say I have this object to work with:
userRequest: {
id: number,
subject: string,
...
orderIds: number[]
...
}
order: {
id: number,
...
clientId: number,
productIds: number[]
}
client: {
id: number,
name: string,
...
}
product: {
id: number,
name: string,
price: number
}
Now, at some point the user will fill a form using that composite object and send it for analysis. But before sending it, it has first to be validated. And I cannot validate in the form because the user is simply entering the data received on paper. If the data is "invalid", a request for more information will be sent.
So, I need to validate the request, but also the order, the products and the client. I am requested to show a "Validating Request" screen and after each element was checked, a "Valid" or "Invalid" screen. Simple enough.
But now, I'm sending http requests and get Observables to deal with. I'm trying to learn more about them and all the available operators and how to mix them, but at the moment, I'm completely lost.
So, I first get an Observable<userRequest> from server. Then, once I get a userRequest, I need to get all the orders from their id's, and when I get an "order", I have to get the client & his products.
All this is done asynchronously, but I cannot get the client or the products until I receive the order, and I need the userRequest to provide the orders. In addition, when I get an order, I need to get both the client AND the products at the "same time" since they both need the same order...? For the grand finale, for every element I get (request, order, client, product) I need to validate it and wait for every element to say "the request is valid" or not.
So to resume:
I need to get an Observable<userRequest> and validate
Now, I have to get an Observable<order[]> and validate each order
For each order, I have to 1) get an Observable<Client> and validate PLUS 2) get an Observable<Product[]> and validate each one
Wait for every observables to complete and check if it's valid or not
Steps 1 and 2 needs to be executed sequentially, but when step 2 completes, I need to execute steps 3.1 and 3.2 for each result of step 2. And wait.
I'm sure it's far from clear, I just hope it clear enough so you guys gets want I want to achieve. If you have any hints for me, please do share!!! ; )
Edit
I do know somehow what needs to be done. But where I lose my cool, is when I need to chain the Observables sequentially (as each one depends on the one before), at various point I need to call a validation method and when it comes to the Client and the Products, both need the Order for it's Id. I did try many, many ways but I just don't grasp the concept completely.
bygrace - No, I don't want the validation to block. It should validate everything as it will result in a request for all the missing or invalid parts, and it should be showed at the end. That why I need a way to know when everything is done so I can check if errors were found.
The request, orders, client and products each comes from their respective services. The service makes an http resquest and returns an Observable. So I need to chain the calls (and when it comes to the Order, I need to get TWO Observables for the same Order Id).
QuietOran - Here's something I tried. It's horrible I know, but I'm so lost right now...
onValidateRequest(requestId: number) {
this.requestService.getUserRequest$(this.requestId)
.do(request => {
this.validateRequest(request);
})
.concatMap(request => this.orderService.getOrdersForRequest$(request.id))
.do(orders => {
this.validateOrders(orders);
})
.concatMap(orders => {
// Now, this is were I'm completely lost
// I manage to get the request and the orders, but in this block, I need to get the client AND the products
// and validate each one as I receive it
// Then return something
})
.do(() => {
// when I validate an element, if there's an error, I simple add it in an array.
// So when ALL the Observable above are completed, this function simply checks
// if there's something in it
this.checkForErrors();
})
.subscribe();
}
I'm going to give you something rough that you can refine with feedback because I'm not clear on the final shape of the data you want back and all. Hopefully this points you in the right direction.
Basically if you want the data from one observable to feed another then you can use switchmap or one of its cousins. If you need the value fed in as well as the result then just lump them together with a combineLatest or something similar.
console.clear();
function getUserRequest(requestId) {
return Rx.Observable.of({ id: 1, subject: 'a', orderIds: [10, 20] })
.delay(500).take(1);
}
function getOrdersForRequest(requestId) {
return Rx.Observable.of([
{ id: 10, clientId: 100, productIds: [ 1000 ] },
{ id: 20, clientId: 200, productIds: [ 1001, 1002 ] }
]).delay(200).take(1);
}
function getClientForOrder(orderId) {
let client;
switch(orderId) {
case 10:
client = { id: 100, name: 'Bob' };
break;
case 20:
client = { id: 200, name: 'Alice' };
break;
}
return Rx.Observable.of(client).delay(200).take(1);
}
function getProductsForOrder(orderId) {
let products;
switch(orderId) {
case 10:
products = [{ id: 1000, name: 'p1', price: 1 }];
break;
case 20:
products = [
{ id: 1001, name: 'p1', price: 2 },
{ id: 1002, name: 'p1', price: 3 }
];
break;
}
return Rx.Observable.of(products).delay(200).take(1);
}
Rx.Observable.of(1)
.switchMap(id => Rx.Observable.combineLatest(
getUserRequest(id),
getOrdersForRequest(id)
.switchMap(orders => Rx.Observable.combineLatest(
Rx.Observable.of(orders),
Rx.Observable.combineLatest(...orders.map(o => getClientForOrder(o.id))),
Rx.Observable.combineLatest(...orders.map(o => getProductsForOrder(o.id)))
)
),
(userRequest, [orders, clients, products]) =>
({ userRequest, orders, clients, products })
)
).subscribe(x => { console.dir(x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
Right now I flattened the results by category. You may want them nested or something like that. This is just a rough pass so provide feedback as needed.
I'm trying to resolve this issue but no matter what I try (based on several suggestions solutions found here as well), I can never make it work.
I would like the Jquery validation plugin to validate automatically all the generated fields from a form. My problem is that it will only work on the first generated field; the validation of the subsequent ones will just be a duplicate of the first.
Here's the pertinent html code:
<form class="someFormClass" method="post">
<span>
<input class="calendarName" name="description" value="<?= value_from_php ?>">
<input class="calendarName" name="description" value="<?= value_from_php ?>">
</span>
</form>
And here's the jQuery validation code:
$(function () {
$('form').each(function () {
$(this).validate({
errorElement: "div",
rules: {
description: {
required: true,
remote: {
url: "calendar/calendar_available/",
type: "post",
data: {
name: function () {
return $(".calendarName").val();
}
}
}
}
},
messages: {
description: {
required: "Description field can't be blank !",
remote: "This calendar already exists."
}
}
});
});
So, as stated, the plug-in behaves properly for the first field. But if I check the values posted in Chrome's Network, the "name" key created in the jQuery validation will always send the value of the first input.
I tried many things (trying to implement on more level of ".each" method in the validation, trying to generate dynamically a specific id for each field to point on (instead of a class), trying to modify the plugin code as suggested here (How to validate array of inputs using validate plugin jquery), but it didn't work.
I think there's something I don't grasp about the logic here.
UPDATE :
So, one of the reasons of my problem is that jQuery validation absolutely requires input with different names. See : Jquery Validation with multiple textboxes with same name and corresponding checkboxes with same name
So, I made a script to generate a different name for each input with the intention to dynamically create validation rules based on those names, following this suggestion : https://stackoverflow.com/a/2700420/3504492
My validation script now look like this :
$(function() {
var rules = new Object();
var messages = new Object();
$('input[name*=description_]:text').each(function() {
var currentName = $("input[name="+this.name+"]").val();
rules[this.name] = {
description: {
required: true,
remote: {
url: "calendar/calendar_available/",
type: "post",
data: currentName
}
}
},
color: {required: true}
};
messages[this.name] = {
description: {
required: "Description field can't be blank !",
remote: "This calendar already exists."
},
color: {required: "Color field can't be blank !"}
};
});
$('form').each(function () {
$(this).validate({
errorElement: "div",
rules: rules,
messages: messages
});
}) });
This almost works. Almost because if I limit the rules et messages to the required keys, it will display the validation each field (if I add the specific name to the message string, it will display on the proper field). But with a most complex rule like mine (with a remote key containing various keys for instance), I get a " Cannot read property 'call' of undefined. Exception occurred when checking element , check the 'description' method." error in the Console.
My guess is that the "description" declaration in the "rules" definition should be dynamic too (the current "name" field being visited).
Any suggestion?
TL;DR - I am trying to use a collected value from a form input as a document _id but am getting a 404.
I've got a modal that opens and collects form data. My first input in the form is:
<input type="text" id="name" name="name" data-ng-model="name" />
When I try to modify the Mongo (Mongoose) model, to use name as the _id, the form wont post. I get a 404 from http://sitegoeshere/#!/somethings/whatever_i_type_in_for_name
Example model:
var SomethingSchema = new Schema({
_id: {
type: String,
default: 'default',
trim: true
}
}
mongoose.model('Something', SomethingSchema);
And in my Angular controller:
$scope.create = function() {
// Create new Something object
var something = new Somethings ({
_id: this.name
});
// Redirect after save
something.$save(function(response) {
$location.path('somethings/' + response._id);
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
};
I've been told that MongoDB allows Strings as the _id type so what gives? Any ideas?
UPDATE: Here's something strange, too. I wanted to see if maybe this was a limitation or bug of Mongoose so I got into the database and created two documents:
> db.subnets.find().pretty()
{ "_id" : ObjectId("546bef63395b0694d51b5cbe"), "description" : "description!" }
{ "_id" : "mystring", "description" : "more description!" }
When I go to my app and try to pull their individual views up, I can see the data for my custom _id document but get a 500 Internal Server Error when I try to access the other.
GET http://localhost:3000/somethings/546bef63395b0694d51b5cbe 500 (Internal Server Error)
GET http://localhost:3000/somethings/mystring 200 OK
The problem is most likely with this.name - looks like it's undefined.
Client data:
accounts = [
Account1 = {
name: 'Dan', phone: 1775123, role: 'Client', email: 'none'
},
Account2 = {
name: 'Messy', phone: 3564576, role: 'Client', email: 'none'
},
Account3 = {
name: 'Sasha', phone: 34231234, role: 'Client', email: 'Sania#mail.ta'
}
];
DOM:
<div ng-repeat="account in accounts" >
<table>
<tr>
<td><input type="checkbox" ng-change="Toggle(account.name)"/>{{ account.name }}</td>
</tr>
</table>
</div>
I just want to figure out what's the best way to change array data in DOM without page reloading. For instance I got some data in view using ng-repeat directive. I selected the option I needed and sent it to NodeJS -> MongoDB. Now I want to get this data in the same place without reloading my page.
It sounds like a very typical question, but I've been trying to find a solution for quite long time.
Just update the data in your controller and angular will update the dom. This is a small example of 2 way data binding which I think is what you want:
Plunker example
In the Toggle method you will put in your service that hits the db and changes the data:
$scope.Toggle = function(idx, account){
$scope.accounts[idx].name = account.name + " Edited";
//replace above with whatever updates the account, ie, businessService.updateAccount(account);
}
I'm assuming that you posted the data to the server and db using a post request (i.e. $http.post(url, data)).
In Angular, all Ajax calls have a a promise to the success method, therefore in the success method, do a get request to the server to retrieve your data i.e.:
$http.post(url, data)
.success(function(){
$http.get(url)
.success(function(data){
updateAccounts(data) // a function to update your accounts array
}
})
On the Server side, your node server should be listening for a get request to the above get url, and then it should use the callback to query the database for the accounts:
app.get(url, function(req, res){
// Query the database for accounts and send back result of query
res.send(200, accounts);
})
Hope that helps!