I have this quickForm:
{{> quickForm id="insertFixie" collection="Fixies" type="insert" doc=seedObject}}
Backed up by this schema:
Fixies = new Meteor.Collection('fixies');
Schema.Fixies = new SimpleSchema({
description: {
type: String,
label: "Description",
trim: true,
optional: true
},
cost: {
type: Number,
label: "Cost",
min: 0,
decimal: true
},
product_id: {
type: String,
autoform: {
omit: true
}
},
});
Fixies.attachSchema(Schema.Fixies);
and this seedObject method:
Template.insertFixie.helpers({
seedObject: function () {
console.log({product_id: this._id});
return {product_id: this._id};
}
});
When that console call directly above happens, it's correct and gives something to this effect:
Object {product_id: "1"}
But when I submit the form with something valid (like "stuff" and "100"), I get this error:
insert error:
Error: Product is required {invalidKeys: Array[1],
validationContext: SimpleSchemaValidationContext,
stack: (...),
message: "Product is required"}
stating that the product_id attribute is required and currently has a value of null.
What am I doing wrong? That product_id is a template dependent value, so something like "autoValue" in the schema doesn't seem like the best way to handle it.
The docs seem to clearly state that I'm using things correctly. From the description of the doc attribute of Auto Form:
For an insert form, you can also use this attribute to pass an object
that has default form values set (the same effect as setting a value
attribute on each field within the form).
And from the description of the value attribute of afFieldInput:
value: Set a specific, potentially reactive, value for the input. If
you have also provided a doc attribute on the autoForm or quickForm,
this value will override the value from the doc object.
What am I missing?
Edit
I added an autoValue field to my schema, just to see what pops up:
autoValue: function (doc) {
console.log(doc)
console.log(this.value)
return "1";
}
This allows the form to correctly submit, but with the incorrect hard-coded value of "1" rather than a useful value from the template. The two console logs show this:
:24 Object {description: "stuff", cost: 50}
:25 undefined
It seems my seedObject value isn't available to autoValue.
Do I have to hijack the onSubmit hooks? Do I have to have hidden form inputs with values supplied from the template? What's the fix here?
It turned out to be a hidden input.
I expanded my form to this:
{{#autoForm id="insertFixie" collection="Fixies" type="insert"}}
<fieldset>
{{> afFormGroup name="description" placeholder="schemaLabel" label=false}}
<div class="form-group{{#if afFieldIsInvalid name='cost'}} has-error{{/if}}">
<div class="input-group">
<div class="input-group-addon">$</div>
{{> afFieldInput name="cost" placeholder="schemaLabel" label=false}}
</div>
{{#if afFieldIsInvalid name="cost"}}
<span class="help-block">{{afFieldMessage name="cost"}}</span>
{{/if}}
</div>
{{> afFormGroup name="product_id" type="hidden" value=_id}}
</fieldset>
<button class="btn btn-primary" type="submit">Insert</button>
{{/autoForm}}
Adding an afFormGroup with type="hidden" did exactly the trick.
Although it still seems to me like the doc argument isn't living up to it's promises.
Related
Objective: I have a form interface that is being loaded with an object's current data for editing. The user opens this modal with the form that is loaded with the current info so they an either edit it or leave it
Currently working: The form loads with the data from my three objects (details, editSubEvents, instructions) and shows properly without issue
My problem: When I edit the fields and hit submit, I'm only currently dumping the submitted data object to make sure I have what I need. I get the eventID fine becasue it won't change and I get it from the original object. However, I need to store the new title, instruction, and subEvents (as an array) in order to submit them because they're obviously different from the origin ones
How can I properly store the new info from these input fields, including storing the new subEvent title and instructions as an array?
<div class="modal-body">
<div class="form-group row" v-for="detail in details">
<p class="modal-title">Title</p>
<input v-model="detail.title" type="text" class="form-control" id="EventTitle" name="EventTitle">
</div>
<div class="form-group row" v-for="subEvent in editSubEvents">
<p class="modal-title">SubEvent Title</p>
<input v-model="subEvent.title" type="text" class="form-control" id="newSubTitle" name="newSubTitle">
<p class="modal-title">SubEvent Instructions</p>
<textarea v-model="subEvent.instructions" type="text" class="form-control" id="newSubInstructions" name="newSubInstructions"></textarea>
</div>
</div>
data() {
return {
details: [],
instructions:[],
editSubEvents:[],
}
},
methods: {
updateEvent() {
let data = {
EventID: this.details[0].event_id,
title:
origin:
instructions:
subEvents: //needs to be an array
};
console.dir(data);
}
}
All of the properties of your data object can be bound to the UI elements (and most of them are, going by your template example code). The properties of the data object are accessible through the Vue component's this.
new Vue({
el: '#vueApp',
data() {
return {
details: [],
instructions:[],
editSubEvents:[],
}
},
methods: {
updateEvent() {
const data = {
EventID: this.details[0].event_id,
title: this.details[0].title,
origin: this.details[0].origin,
instructions: this.instructions,
subEvents: this.subEvents,
};
console.dir(data);
}
}
}
I'm setting a model with form, but I have a problem to set a "MyModel" with a form
This is for the purpose of optimizing the handling of the forms
public myModel = new MyModel();
this.myForm = this.formBuilder.group({
firstName: new FormControl({
value: this.myModel.firstName,
disabled: false
}),
middleName: new FormControl({
value: this.myModel.middleName,
disabled: false
}),
lastName: new FormControl({
value: this.myModel.lastName,
disabled: false
}),
age: new FormControl({
value: this.myModel.age,
disabled: false
})
});
when I submit a "submit" with a button, that shows me the "this.myForm" with the elements that I added in the form
but it seems that I would not be establishing a connection as a "TwoDataBinding"
I also do not want to do this code since I see it very redundant
also
when it comes to many forms and even worse if you decide to change or refactor the attributes of that object
this.myModel.firstName = this.myForm.controls['firstName'].value;
this.myModel.lastName = this.myForm.controls['lastName'].value;
this.myModel.middleName = this.myForm.controls['middleName'].value;
this.myModel.age = this.myForm.controls['age'].value;
You can see the complete code here:https://stackblitz.com/edit/form-model-hammer
of a form model, if you want to make changes makes a FORK to share, thanks:
also for the purpose of avoiding this alert in the picture
If you want to use 2-way binding, you should use template-driven forms instead. It allows you to use ngModel to create two-way data bindings for reading and writing input-control values.
The principles of reactive forms follows the 'one-way' rule, whereby you follow an immutable method of managing the state of your forms, such that there is greater separation of concern between your template and component logic. You can read more about the advantages of reactive forms on the above link.
If you think reactive forms is not what you want, you should revert to using template driven forms, as stated on the first paragraph.
One thing to take note, you should not use ngModel with reactive forms, as this will defeat the purpose of immutability.
However, if you are planning to stick to using reactive forms, you can simplify your code by doing this instead:
1) Initialising and declaring your reactive forms.
this.myForm = this.formBuilder.group({
firstName: [{value: this.myModel.firstName, disabled: true}],
middleName: [this.myModel.middleName],
lastName: [this.myModel.Name],
age: [this.myModel.age],
});
2) Get reactive form data:
// since the properties of myModel and myForm FormControl names are the same
this.myModel = {...this.myForm.value};
3) Update reactive form data:
this.myForm.patchValue(this.myModel);
You should stop using ngModel with Reactive forms as it is deprecated now .
You can simplify the code like below :
this.myModel.firstName= 'FIRST NAME';
this.myForm = this.formBuilder.group({
firstName:[{
value: this.myModel ? this.myModel.firstName : '',
disabled: false
}],
middleName: [{
value: this.myModel ? this.myModel.middleName : '',
disabled: false
}],
lastName: [{
value: this.myModel ? this.myModel.lastName : '',
disabled: false
}],
age:[{
value: this.myModel ? this.myModel.age : '',
disabled: false
}]
});
Listen to (ngOnSubmit) event and write a function to save the form values .
This can be achieved in the below way :
save(myForm : any){
let form = myForm as MyModel;
console.log(form);
form.otherProperties = 'nothing';
}
Or :
save(myForm : MyModel){
let form = JSON.parse(JSON.stringify(myForm)); //for copy
console.log(form);
form.otherProperties = 'nothing';
console.log( 'added a new property', form);
}
And in your html :
<div>
<form [formGroup]="myForm" (ngSubmit)='save(myForm.value)'>
<label>
<span>
Fisrt name:
</span>
<input type="text" formControlName="firstName">
</label>
<label>
<span>
Middle name
</span>
<input type="text" formControlName="middleName">
</label>
<label>
<span>
Last name
</span>
<input type="text" formControlName="lastName">
</label>
<label>
<span> Age: </span>
<input type="number" formControlName="age">
</label>
<div style="display: block">
<button (click)="onShowModel()">
show model
</button>
</div>
<div style="display: block">
<button>
set model from form
</button>
</div>
</form>
</div>
<div>
<p class="red"> from model : </p>
<span class="red"> Model: {{myModel | json}} {{nothing}}</span>
</div>
<div>
<p class="blue"> from form, binding model : </p>
<span class="blue"> Model: {{myForm.value | json}}</span>
</div>
I have also forked your example : Example
I've got a form with about 10 select elements built from an array in my Vue data.
The array of selectors is empty initially and then an AJAX call populates the array and Vue builds the HTML - I've kept the snippet below simplified just to demonstrate the issue I'm having with v-model
I want to create an object that has all the selected values in it, so I'm trying to use v-model="selected[ selector.name ]" as per the example below.
I want to easily be able to ask for selected.make or selected.fuel
Now this works if I initialize the selected property like this:
selected: { make: 'audi', fuel: 'petrol' }
If I leave it blank, like in the example, {}, then it doesn't get updated.
I don't want to manually hardcode all the properties of selected, I only want to be listing them once in the server side code that gets sent via AJAX
So am I missing something completely obvious, should I be doing this in a different way?
Maybe a method to find the dropdown that matches a field name and returns the value? Just that doesn't seem like a very Vue thing to do.
var app = new Vue({
el: '#example',
data: {
selectors: [
{
name: 'make',
options: ['audi','bmw']
},
{
name: 'fuel',
options: ['petrol','diesel']
}
],
selected: {}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="example">
<template v-for="selector in selectors">
<select v-model="selected[ selector.name ]">
<option v-for="option in selector.options">{{option}}</option>
</select>
</template>
<p>
{{selected.make}}
<br />
{{selected.fuel}}
</p>
</div>
it's probably becuase you're not setting new keys on an object with this.$set
try:
this.$set(this.selected, 'make', 'audi')
Not using this.$set - alias of Vue.set - will mean Vue doesn't set the new key as reactive, and in turn won't be watching for any updates to it, docs: https://v2.vuejs.org/v2/api/#vm-set
var app = new Vue({
el: '#example',
data: {
selectors: [{
name: 'make',
options: ['audi', 'bmw']
}, {
name: 'fuel',
options: ['petrol', 'diesel']
}],
selected: null,
},
created () {
// this would happen following your ajax request - but as an example this should suffice
this.selected = {}
this.selectors
.forEach((selector) => {
this.$set(this.selected, selector.name, '')
})
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.3/vue.js"></script>
<div id="example">
<div v-if="selected">
<select v-model="selected[selector.name]" v-for="selector in selectors">
<option :value="option" v-for="option in selector.options">
{{option}}
</option>
</select>
<p>make: {{selected.make}}<p>
<p>fuel: {{selected.fuel}}</p>
<pre>{{ selected }}</pre>
</div>
</div>
I'm new to Vue and I would like some help getting a value from an input field:
In my form I have:
<input type="hidden" id="groupId" value="1">
If I was using jQuery I would do:
var group_id = $('#groupId').val();
However, in Vue I don't know how to bind the hidden field:
<div id="app">
<input type="text" v-model="groupId"> //Where do I put the value?
</div>
new Vue({
el: '#app',
data: {
groupId: //What do I put here to get the field's value?
}
How can I achieve this?
Update to the update: See this answer. Previously updated answer was wrong.
Original answer:
In Vue, you don't get things from the view and put things into the view. Vue does that. You do all manipulations in the viewmodel, and make bindings in the view so that Vue knows how to synchronize it. So you'd bind the input to your model data item:
<input type="hidden" id="groupId" v-model="groupId">
and set its value in your viewmodel:
data: {
groupId: 1
}
I had the same question. I'm working with Vue + Laravel.
For me, the solution was simple after searching and not finding a concrete solution in the Vue documentation.
Simply:
document.getElementById('MyId').value;
Details in → https://www.w3schools.com/jsref/prop_text_value.asp
It is not the most efficient solution, but it works for now!
Greetings.
Working sample of getting value from input field in this case it is hidden type:
<input type="hidden" name="test">
<script>
new Vue ({
created () {
const field = document.querySelector("input[name=test]").value
console.log(field)
}
})
</script>
this code helped me
i hope that this work with you
define the input
<div class="root">
<input type="hidden" ref="groupId" value="1">
<button type="button" v-on:click="get_id()">test</button>
</div>
define the method
new Vue({
el: ".root",
data: {
id: null,
}
methods: {
get_id() {
this.id = this.$refs.groupId.value;
}
}
});
// if you want it displayed on your page, use {{ groupId }}
/* you can get the value by using #change.enter=".." #keypress.enter="getInputValue",
or #input="getInputValue" or #click="getInputValue" using button,
or if it is with a form element, #submit.prevent="getInputValue" */
/* #keypress.enter tracks input but only calls the function when the Enter key
is pressed, #input track changes as it's being entered */
// it is important to use event.preventDefault() when using #change or #keypress
<div id="app">
<input type="text" v-model="groupId">
<p> {{ groupId }} </p>
<button #click="getInputValue">Get Input</button>
</div>
new Vue({
el: '#app',
data: {
groupId: //What do I put here to get the field's value?
// for what to put there, you can use an empty string or null
groupId: "",
},
// to get the value from input field
methods: {
getInputValue: function() {
if(this.groupId !== "") {
console.log(this.groupId);
}
},
}
})
look at this I did it in laravel, vuejs, vuetable2 and children's row, and don't use the v-model:
this.$refs['est_'+id_det].localValue
en VUE:
<div class="col-md-3">
<b-form-select class="form-control selectpicker" :ref="'est_'+props.row.id_detalle_oc"
:value="props.row.id_est_ven" v-on:change="save_estado(props.row.id_detalle_oc)">
<option value="0">Sin estado</option>
<option value="1">Pendiente</option>
<option value="2">Impresa</option>
<option value="3">Lista</option>
</b-form-select>
in methods
methods: {
save_estado:function (id_det){
var url= 'ordenes-compra/guardar_est_ven'
var id_estado = this.$refs['est_'+id_det].localValue
axios.post(url,{
id_det: id_det,
id_est_ven: id_estado,
est_ven: est_ve
}).then(function (response) {
var respuesta= response.data;
if(respuesta == "OK"){
swal({
type: 'success',
title: '¡Éxito!',
text: 'Estado modificado',
confirmButtonText: 'Entendido',
})
}
})
.catch(function (error) {
console.log(error);
});
},
I hope it helps, I've been hanging around for a while.
Regards
Hi you can also try the following:
const input = this.$el.firstElementChild;
in case you are using TypeScript, declare input as:
: HTMLInputElement
Then, you can simply get the value if you do:
input.value
Hope it helps!
Ok, this does the job: document.querySelector('#groupId').getAttribute('value');
I am posting a form to a url from a page that displays backbonejs models.
This is how my backbonejs model looks like in the form:
Form:
<form class="form-horizontal" action="profit" method="post">
<fieldset>
<!-- Form Name -->
<legend>Form Name</legend>
<!-- Button -->
<div class="control-group">
<div class="controls">
<div id="example-1-result" class="backgrid-container"></div>
<button id="profit" name="profit" class="btn btn-primary">Button</button>
</div>
</div>
</fieldset>
</form>
JavaScript:
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="../static/js/bootstrap.min.js"></script>
<script>
var Trade = Backbone.Model.extend({});
var Trades = Backbone.Collection.extend({
model: Trade,
url: "fodata"
});
var columns = [
{
name: "trade_id",
label: "Trade Id",
// The cell type can be a reference of a Backgrid.Cell subclass, any Backgrid.Cell subclass instances like *id* above, or a string
cell: "string" // This is converted to "StringCell" and a corresponding class in the Backgrid package namespace is looked up
},
{
name: "order_id",
label: "Order Id",
// The cell type can be a reference of a Backgrid.Cell subclass, any Backgrid.Cell subclass instances like *id* above, or a string
cell: "string" // This is converted to "StringCell" and a corresponding class in the Backgrid package namespace is looked up
},
{
name: "trade_date",
label: "Trade Date",
cell: "datetime",
},
{
name: "trade_time",
label: "Trade Time",
cell: "datetime",
},
{
name: "contract_description",
label: "Contract Description",
cell: "string" // An integer cell is a number cell that displays humanized integers
},
{
name: "expiry_date",
label: "Expiry Date",
cell: "datetime",
},
{
name: "buy_quantity",
label: "Buy Quantity",
cell: "integer" // An integer cell is a number cell that displays humanized integers
}, {
name: "buy_rate",
label: "Buy Rate",
cell: "number",
},
{
name: "sale_quantity",
label: "Sale Quantity",
cell: "integer" // An integer cell is a number cell that displays humanized integers
}, {
name: "sale_rate",
label: "Sale Rate",
cell: "number",
}
];
var trades = new Trades;
var grid = new Backgrid.Grid({
columns: columns,
collection: trades
});
// Initialize a new Grid instance
var refreshgrid = function(){
$("#example-1-result").prepend(grid.render().$el);
}
</script>
Now, while submitting, I need to submit the trades JSON data but I'm not able to get the model to submit.
How do I achieve this? Do I need to use backbonejs forms?
Backgrid is supposed to give you something to quickly edit all the models you give it to it (through the collection) using the normal backbone mechanisms. So technically, you shouldn't use a form to wrap it, and when editing each Trade model, the Trade model should be saved() after the end of the edit. Backgrid is a nice way to wrap basic CRUD on top of a resource.
If that's not the behavior you want, then maybe Backgrid isn't what you need?
That being said, nothing prevents you at anytime, no matter what's in the form, to do something like:
$("form").on("submit", function(event){
//Don't send the form, stay on the page
event.preventDefault();
//Transform the collection of Trades into an array of JSONified Trade
data = trades.map(function(trade){
return trade.toJSON();
});
//Post this to the server
$.post("url", {trades: data}, ... );
return false;
});
But that seems odd.
If I misunderstood, maybe you can clarify your intent a bit? Hope this helps!
You should just be able to serialize the model and POST it.
See: http://api.jquery.com/serialize/
If you .serialize the data you want and send that as part of your POST request it should work. Alternatively if you're looking for something a bit more advanced take a look at syphon:
http://lostechies.com/derickbailey/2012/05/17/backbone-syphon-serialize-form-inputs-to-javascript-objects/
Serializing is most likely the key to what you want to achieve.