I have like this template currently:
<div>
<div v-for="(item, key) in items" :key="key">
<div>
<input type="text" :value="item.title">
</div>
<div>
<input type="text" :value="item.description">
</div>
<div class="actions">
<button type="button" #click="discardChanges(item)" :disabled="!itemChanged">Discard changes</button>
<button type="button" #click="sendChanges(item)" :disabled="!itemChanged">Save</button>
</div>
</div>
</div>
<script type="text/javascript">
export default {
data() {
return {
itemChanged: false,
items: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
]
}
},
methods: {
sendChanges(item) {
// Send API request to update item
},
discardChanges(item) {
// Set old value if item changed
}
}
}
</script>
In this case I generate dynamic inputs from array of items. I need to correctly control my action buttons by detecting current item changes.
For example user will change second item title and will click to Discard changes button. In this case how I can set old value to input?
Also how I can correctly disable or enable action buttons by comparing ch
I have made use of another array called oldValues and modified the methods accordingly. Also I suggest you to use v-model instead of :value
<div>
<div v-for="(item, key) in items" :key="key">
<div>
<input type="text" v-model="item.title">
</div>
<div>
<input type="text" v-model="item.description">
</div>
<div class="actions">
<button type="button" #click="discardChanges(key)" :disabled="!itemChanged">Discard changes</button>
<button type="button" #click="sendChanges(item, key)" :disabled="!itemChanged">Save</button>
</div>
</div>
</div>
<script type="text/javascript">
export default {
data() {
return {
itemChanged: false,
oldValues: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
],
items: [
{
title: "Apple",
description: "The bigger company of the world"
},
{
title: "Amazon",
description: "The bigger online store of the USA"
},
]
}
},
methods: {
sendChanges(item) {
// Send API request to update item
this.oldValues[key]=item;
},
discardChanges(item) {
// Set old value if item changed
this.items[key]=this.oldValues[key];
}
}
}
</script>
Related
I have users with their own checkboxes, I need to do so that when you select a specific user by clicking on the checkbox, then when you click on the "Get user id" button, get the user ID in the getUserId method.
Here is the code in CodeSandbox
<template>
<div>
<div class="user" v-for="(user, i) in items" :key="i">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<input type="checkbox" />
</div>
<button #click="getUserId()">Get user id</button>
</div>
</template>
<script>
export default {
methods: {
getUserId() {},
},
data() {
return {
items: [
{
id: 1,
name: "Alex",
age: 23,
},
{
id: 2,
name: "Robert",
age: 33,
},
{
id: 3,
name: "Jacob",
age: 55,
},
],
};
},
};
</script>
Seems you want to collect the checked user IDs. To do so, you should bind your checkbox models to an array and set the value to the user.id
new Vue({
el: "#app",
methods: {
getUserId() {
console.log("userIds", this.userIds)
},
},
data() {
return {
items: [{"id":1,"name":"Alex","age":23},{"id":2,"name":"Robert","age":33},{"id":3,"name":"Jacob","age":55}],
userIds: [] // start with an empty array
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<!-- Note: the `user.id` makes for a much better `key` -->
<div class="user" v-for="user in items" :key="user.id">
<p>{{ user.name }}</p>
<p>{{ user.age }}</p>
<!-- Set the checkbox value to `user.id` and bind the model to your array -->
<input type="checkbox" :value="user.id" v-model="userIds" />
</div>
<button #click="getUserId()">Get user id</button>
</div>
See https://v2.vuejs.org/v2/guide/forms.html#Checkbox
I'm trying to append new input fields based on a condition, I will describe the workflow to help you understand
First stage is to press this button to implement 2 functions(1 is to move to other fieldset in the staged form, second function is to append the inputs:
<input type="button" name="secondBtn" class="next action-button" value="Next" id="secondBtn" #click="nextPlusappend"/>
nextPlusappend:
nextPlusappend() {
this.isNextClicked();
this.appendFields();
}
appendFields:
//this.platform initllized as 'one' so the condition is true.
if(this.platform === 'one'){
this.inputFields.push({
Username: '',
Password: '',
AffiliateID: '',
CI: '',
GI: '',
})
}
And I want to append all the fields from the function to this fieldset:
<div v-if="currentPage === 2">
<fieldset id="fieldset3" v-for="(param, index) in inputFields" :key="index">
<h2 class="fs-title">API Credentials</h2>
<h3 class="fs-subtitle">Step 3- Add any parameter for the integration</h3>
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
<input type="button" name="previous" class="previous action-button" value="Previous" #click="isPreviousClicked"/>
<input type="submit" name="submit" class="submit action-button" value="Create a Ticket" id="excel"/>
</fieldset>
</div>
How can I append this without hard code all the input fields as I did here:?
<input v-model="param.Username" type="text" name="`inputFields[${index}[Username]]`" placeholder="userName">
This is designated to be dynamic, what do i mean?
I mean that if the this.platform is equal to "one" there will be a unique fields, and if this.platform equal to "two" for example there will be other unique fields.
Don't think like "pushing a form field", rather think like "adding a new item to the dataset" (and of course, its displayed UI is a form field).
Let me give an example:
Vue.component("FormField", {
props: ["label", "value"],
computed: {
val: {
get() {
return this.value
},
set(val) {
this.$emit("update:value", val)
}
},
},
methods: {
handleClickAdd() {
this.$emit("click-add-field")
}
},
template: `
<div>
<label>
{{ label }}: <input type="text" v-model="val" />
</label>
<button
#click="handleClickAdd"
>
+ ADD
</button>
</div>
`,
})
new Vue({
el: "#app",
data() {
return {
formFields: [{
label: "Field 1",
value: null,
}],
}
},
methods: {
handleClickAddField() {
const item = {
label: `Field ${ this.formFields.length + 1 }`,
value: null,
}
this.formFields = [...this.formFields, item]
},
},
template: `
<div
class="container"
>
<div
class="col"
>
<h4>FIELDS:</h4>
<hr>
<form-field
v-for="(field, i) in formFields"
:key="i"
:label="field.label"
:value.sync="field.value"
#click-add-field="handleClickAddField"
/>
</div>
<div
class="col"
>
<h4>FIELD VALUES:</h4>
<hr>
<div
v-for="(field, i) in formFields"
:key="i"
>{{ field.label }}: {{ field.value }}</div>
</div>
</div>
`,
})
.container {
display: flex;
}
.col {
padding: 0 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
You can see, that on ADD I just added a new item in the formFields - the values are bound in the template to a child-component, that handles the actual representation of the fields.
On the right side of the snippet, you can see another benefit of decoupling data from UI: I created another representation of the same data source - that immediately reacts to any changes!
My values on my vue js form are blank or undefined when i submit them for some reason. I am trying to log e.target.name.value to the console to check my form values.
Is there an easier way to do this in vue for this setup? I've been trying different methods and I fear i'm trying to homogenize my vanilla js with vue and creating more problems for myself.
my vue data:
new Vue({
el: '#grocery_list',
data: {
selected: null,
list: [
{
id: 0,
category: 'Baked goods',
food: ['bread','cookie','butter','powder']
},
{
id: 1,
category: 'meats',
food: ['chicken','turkey','beef']
},
{
id: 2,
category: 'fruits',
food: ['bannana','apple','pineapple']
},
{
id: 3,
category: 'canned goods',
food: ['tomatoes','green beans','corn']
},
{
id: 4,
category: 'veggies',
food: ['broccoli','celery','lettuce']
},
{
id: 5,
category: 'pantry',
food: ['broom','mop','dried beans']
},
],
isHidden: true,
form: {},
},
methods:{
addItem: function(e){
console.log(form)
},
viewItemsinCat: function(){
this.isHidden = false
},
checkItem: function(){
}
}
})
my html
<div class="addItem" id="addItem" #submit.prevent="addItem">
<form>
<label for="addItem">Add food item</label>
<input v-model="form.foodName" type="text" name="foodName"></input>
<div>
<select v-model="form.category" id="food">
<option v-for="item in list" name="item">{{item.category}}</option>
</select>
</div>
<div>
<button type="submit">Add Item</button>
</div>
</form>
</div>
In vuejs you don't have to use the names or ids to get value of an input all you have is to use v-model which is reactive and will update all the form values instantly
check this out
<template>
<div class="addItem" id="addItem" #submit.prevent="addItem">
<form>
<label for="addItem">Add food item</label>
<input v-model="form.foodName" type="text" name="foodName"></input>
<div>
<select v-model="form.category" id="food">
<option v-for="item in list" name="item">{{item.category}}</option>
</select>
</div>
<div>
<button type="submit">Add Item</button>
</div>
</form>
</div>
</template>
<script>
export default {
data: () => ({
form: {}
}),
methods: {
addItem: function(){
console.log(this.form)
}
}
}
</script>
How can I have different V-MODEL on every object that i generate
I am trying to make an sample cupcake website that can generate multiple forms in one submit.
But when I generate 2 field, the inputs of the 2 generated field bound by each other inputs.
This is the code I am trying to generate:
<template>
<div>
<button #click="cupcakes.push(def)">Add Cup Cake</button>
<div v-for="(cupcake, index) in cupcakes" :key="index">
<input type="text" v-model="cupcakes[index].name">
<input type="text" v-model="cupcakes[index].description">
<input type="text" v-model="cupcakes[index].type">
<input type="text" v-model="cupcakes[index].prize">
<input type="text" v-model="cupcakes[index].color">
</div>
<button #click="onSubmit">Create Cupcate</button>
</div>
</template>
<script>
export default {
data() {
return {
cupcakes: [],
def: {
name: '',
description: 'Originals',
type: 'small',
prize: 500,
color: 'color'
}
}
},
methods: {
onSubmit() {
console.log(this.cupcakes);
}
}
}
</script>
I tried to do other things but it doesn't work.
How can I dis bind the 2 field and when I submit it will take the inputs that I type or input.
You are pushing n times the same objet (def) into your cupcakes Array. def is a reference to an object. So when you update cupcakes[n], you are just updating the def values.
What you need to do is send a copy of that object into the cupcakes object:
<button #click="cupcakes.push(JSON.parse(JSON.stringify(def)))">Add Cup Cake</button>
I think a better pattern would be to make a method that returns you a new cupcake:
<template>
<div>
<button #click="cupcakes.push(getNewCupcake())">Add Cup Cake</button>
<div v-for="(cupcake, index) in cupcakes" :key="index">
<input type="text" v-model="cupcakes[index].name">
<input type="text" v-model="cupcakes[index].description">
<input type="text" v-model="cupcakes[index].type">
<input type="text" v-model="cupcakes[index].prize">
<input type="text" v-model="cupcakes[index].color">
</div>
<button #click="onSubmit">Create Cupcate</button>
</div>
</template>
<script>
export default {
data() {
return {
cupcakes: []
};
},
methods: {
onSubmit() {
console.log(this.cupcakes);
},
getNewCupcake() {
return {
name: "",
description: "Originals",
type: "small",
prize: 500,
color: "color"
}
}
}
};
</script>
I have a collection of objects that are of types: text, selectoptions and multiselectoptions. I need to display them as editable inputs based on their type.
For example, a text object:
<input type="text" name="caption" value="{{option.value}}" />
A selectoption/multiselectoptions:
<div ng-repeat="value in option.values">
<input type="text" name="{{option.id}}[value][{{value.id}}]" value="{{value.value}}" />
<input type="text" name="{{option.id}}[caption][{{value.id}}]" value="{{value.caption}}" />
</div>
Is this the correct way to do this? Is there a better way to represent it?
Example of the JSON objects:
FORM: {
options: [
{
type: "select",
values: [
{
value: 0,
caption: "Some option"
},
{
value: 1,
caption: "Some other option"
}
]
},
{
type: "text",
caption: "Some text item"
}
]
}
You could use ng-if to display the correct form element based on your model. Here is an example in plunker based on your code.
<form novalidate class="simple-form">
<div ng-repeat="field in FORM.options">
<input type="text" ng-model='field.caption' ng-if="field.type == 'text'" /><br />
<div ng-if="field.type != 'text'">
<div ng-repeat="value in field.values">
Option: <input type="text" name="{{option.id}}[value][{{value.id}}]" value="{{value.value}}" /><br/>
Caption: <input type="text" name="{{option.id}}[caption][{{value.id}}]" value="{{value.caption}}" /><br/>
</div>
</div>
</div>
<button ng-click="submit()">Save</button>
</form>
I check the type field.type and display different HTML in the main ng-repeat.
The app assign your model to FORM:
$scope.FORM = {
options: [
{
type: "select",
values: [
{
value: 0,
caption: "Some option"
},
{
value: 1,
caption: "Some other option"
}
]
},
{
type: "text",
caption: "Some text item"
}
]
};
I also added a submit button that display the model in the Javascript console, so you can see that the data is being updated when you change the values:
<button ng-click="submit()">Save</button>
Try ng-switch which will switch to corresponding HTML based on the type from the JSON.
<div ng-repeat="opt in FORM.options" ng-switch on="opt.type">
<select ng-switch-when="select">
<option ng-repeat="val in opt.values" value='{{val.value}}'>{{val.caption}}</option>
</select>
<input type="text" ng-model="opt.caption" ng-switch-when="text"/>
</div>
Add more MultiSelect types with ng-switch-when = "multiselect". If the type is not specified, set a ng-switch-default to default html.
Working Plunker