How to isolate component in Vue.js - vue.js

I have a problem at the beginning of my Vue education.
I made a small app. How can I isolate component?
After clicking on the arrow I'd like to open only one section of information.
Here's the code and live demo:
https://lemonwm.github.io/app_vue/
https://github.com/lemonWM/app_vue

If you plan to iterate through your recipes, you can add a property expanded: false for each recipe and toggle this one (instead of a global data property):
<div class="element-menu" v-for="recipe in recipes">
<div class="main-element">
<h2>{{ recipe.title }}</h2>
<div>
<button v-on:click='recipe.expanded = !recipe.expanded'><img src="img/arrow_06.png" alt=""></button>
</div>
</div>
<div class="desribe-element">
<div v-if='recipe.expanded'>
<div class="recipe-ingredience-left">
<h3>Składniki</h3>
<p v-for="ingredient in recipe.ingredients">{{ ingredient }}</p>
</div>
<div class="recipe-ingredience-right">
<h3>Przygotowanie</h3>
<p>{{ recipe.description }}</p>
</div>
</div>
</div>
</div>
data() {
return {
recipes: [
{
title: "Spaghetti",
ingredients: [
"Podwójna porcja makaronu",
"500g sera białego tłustego",
"2 łyżeczki soli (lub do smaku)",
"1/2 łyżeczki zmielonego pieprzu"
],
description: "Lorem...",
expanded: false //<-- here
},
{
title: "Carbonara",
ingredients: [
"...",
],
description: "..",
expanded: false,
},
]
}
}

Related

Vue v-model/v-for doesn't update on mount, but after first manual change

I have a dropdown list "functions" that is filled with database entries and a dropdown list with 2 hardcoded entries. When the vue website is opened the dropdown list remains empty but as soon as I change the value of the other dropdown field the desired data from the database is available.
I'm a bit confused because I expected that adding "retrieveFunctions()" into the mounted() function would trigger the v-for, and even more confused that changing something in another select field suddenly triggers it.
The HTML code:
<template>
<div class="submit-form">
<div v-if="!submitted">
<div class="row">
<div class="col-sm-12">
<p><a style="width:500px" class="btn btn-info" data-toggle="collapse" href="#generalInformation" role="button" aria-expanded="true" >
General Information</a></p>
<div class="collaps show" id="generalInformation">
<!-- NAME -->
<div class="form-group">
<input placeholder="Name" type="text" class="form-control"
id="name" required v-model="component.name" name="name">
</div>
<!-- DOMAIN -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<label style="width:100px" class="input-group-text" for="inputGroupDomain">Domain</label>
</div>
<select v-model="component.domain"
class="custom-select"
id="inputGroupDomain"
>
<option value="Power System">Power System</option>
<option value="ICT">ICT</option>
</select>
</div>
<!-- FUNCTION -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<label style="width:100px" class="input-group-text" for="inputGroupFunction">Functions</label>
</div>
<select v-model="_function" class="custom-select" id="inputGroupFunction">
<option :class="{ active: index == currentIndex }"
v-for="(_function, index) in functions"
:key="index"
value= _function.name>
{{ _function.name }}
</option>
</select>
</div>
</div>
<p>
<button #click="saveComponent" class="btn btn-success">Add Component</button>
</p>
</div>
</div>
</div>
<div v-else>
<h4>Component was added succesfully!</h4>
<button class="btn btn-success" #click="newComponent">Proceed</button>
</div>
The script part:
<script>
import FunctionDataService from "../services/FunctionDataService";
export default {
name: "add-component",
data() {
return {
component: {
id: null,
name: "",
type: "",
domain: "",
},
submitted: false
};
},
methods: {
retrieveFunctions() {
FunctionDataService.getAll()
.then(response => {
this.functions = response.data;
console.log(response.data);
})
.catch(e => {
console.log(e);
});
},
refreshList() {
this.retrieveFunctions();
},
},
mounted() {
this.retrieveFunctions();
}
};
</script>
refreshList() {
this.retrieveFunctions();
},
},
mounted() {
this.retrieveFunctions();
}
};
</script>
State in the beginning: Dropdown list empty
State after selecting something in the upper dropdown list: Database entries are visible and correct
You need to initiate all responsive properties on the data return object with either a value (empty string, array, object, etc) or null. Currently it's missing the _function attribute used in the select v-model and the functions array used in the v-for. You can try to change the data to the following:
data() {
return {
_function: "",
functions: [],
component: {
id: null,
name: "",
type: "",
domain: "",
},
submitted: false
};
},

How can I add a task to a list in my Vue 2 to-do app?

I am trying to add a task to a tasklist in Vue based on the input and add task button, but I keep getting the error "taskList is not defined". Does anybody see how to fix this problem? The code is as following:
<template>
<div id="input">
<form>
<input v-model="task.name">
<button v-on:click="addTask" v-bind:value="task.name">+</button>
</form>
<ol>
<div v-for="task in taskList" :key="task.id">
{{ task.name }}
<div v-if="task.completed">
<h2> Done </h2>
</div>
<div v-else>
<h2> Not done</h2>
</div>
</div>
</ol>
</div>
</template>
<script>
export default {
name: 'AddTask',
data: function() {
return {
taskList: [
{
name: 'task', completed: false, id: 3
}
] }
},
methods: {
addTask: function (task) {
taskList.push(task);
alert('test');
}
}
}
</script>
Ps. any other Vue tips are welcome as well.
You need to separate out your taskList and the current task you're adding, decouple it as a new object, then add it to your taskList array.
When referring to items in your data object you need to use the this keyword – e.g this.taskList rather than taskList:
new Vue({
el: "#app",
data: {
id:1,
taskList: [],
currentTask:{
completed:false,
name:'',
id:this.id
}
},
methods: {
addTask: function() {
let newTask = {
completed:this.currentTask.completed,
name:this.currentTask.name,
id:this.currentTask.id
}
this.taskList.push(newTask);
this.id++;
//alert('test');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="input">
<ol>
<li v-for="task in taskList" :key="task.id">
{{ task.name }}
<input type="checkbox"
:checked="task.completed"
#change="task.completed = !task.completed">
<span v-if="task.completed">
Done
</span>
<span v-else>
Not Done
</span>
</li>
</ol>
<input type="text" v-model="currentTask.name">
<button v-on:click="addTask">+</button>
</div>
</div>
From what I see in your template you use tasklist but you define it as taskList You will want to make sure your names are in the same case. Usually you'll see camelCase in vue, but other popular ones are snake_case and PascalCase

Somthing when wrong. vue-select2 not working in vue2, How doit right?

Haixing-Hu/vue-select in version vue-select2 not working in vue2 and need some help... I do everything like the doc but nothing happends
this is my template code...
<template>
<div>
<div class="form-group">
<label for="select2" class="col-sm-3 control-label">
A searchable select with names and localized in en-US:
</label>
<div class="col-sm-5">
<vue-select
class="vue-select2"
name="select2"
:options="options2"
:model.sync="result2"
:searchable="true"
language="en-US"
>
</vue-select>
</div>
<div class="col-sm-4">
<p class="form-control-static">
Selected Result: <span class="vue-result2">{{ result2 }}</span>
</p>
</div>
</div>
</div>
</template>
this is my script code...
<script>
export default {
components: {
"vue-select": require("vue-select2")
},
data() {
return {
serverErrors: {},
result2: '',
options2: [
{
text: 'name1',
value: 'value1',
},
{
text: 'name2',
value: 'value2',
},
],
}
}
}
</script>
bud got this... The select2 do not show and got a uggly warning...
[Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <VueSelect>

To do List with Vue js 2 using component or v-model

Hello I have here one code with two "todo list" implementations in Vuejs but I have a problem.
1 Using a vue component i am getting a waring about how to use the parent variable.
2 Doing it on the main function I cannot keep the old value for the discard implementation.
please find the working code
Running! todo list in codepen
Vue.component('ntodo-item', {
template: '\
<transition name="fade">\
<div id="if" class="row" v-if="edit">\
<div class="col-md-7">\
<input class="form-control" v-model="title">\
</div>\
<div id="sssss" class="col-md-5">\
<button class="btn btn-danger roundButton" v-on:click="$emit(\'edit\')">Discard</button>\
<button class="btn btn-success roundButton" v-on:click="updateValue">Save</i></button>\
</div>\
</div>\
<div id="else" class="row" v-else>\
<div class="col-md-7">\
{{ title }}\
</div>\
<div id="ssaaas" class="col-md-5">\
<button class="btn btn-danger roundButton" v-on:click="$emit(\'remove\')">Remove</button>\
<button id="aaa" class="btn btn-default roundButton" v-on:click="$emit(\'edit\')">Edit</button>\
</div>\
</div>\
</transition>\
',
props: [
'title' ,
'edit'
],
methods: {
updateValue: function () {
this.$emit('input', this.title);
}
}
})
var app14 = new Vue({
el: '#app-14',
data: {
newTodoText: '',
newTodoText2: '',
todos: [
{
id: 1,
title: 'Do the dishes',
edit:0
},
{
id: 2,
title: 'Take out the trash',
edit:0
},
{
id: 3,
title: 'Mow the lawn',
edit:0
}
],
todos2: [
{
id: 1,
title: 'Do the dishes',
edit:0
},
{
id: 2,
title: 'Take out the trash',
edit:0
},
{
id: 3,
title: 'Mow the lawn',
edit:0
}
],
nextTodoId: 4,
nextTodoId2: 4
},
methods: {
addNewTodo: function () {
this.todos.push({
id: this.nextTodoId++,
title: this.newTodoText,
edit:0
})
this.newTodoText = ''
this.todos = _.orderBy(this.todos, 'id', 'desc');
},
editTodo: function (item){
// console.log(item.title)
item.edit^= 1
},
updateValue: function (item, newValue){
item.title=newValue
item.edit^= 1
},
addNewTodo2: function () {
this.todos2.push({
id: this.nextTodoId2++,
title: this.newTodoText2,
edit:0
})
this.newTodoText2 = ''
this.todos2 = _.orderBy(this.todos2, 'id', 'desc');
},
editTodo2: function (item){
console.log(item.title)
item.edit^= 1
},
deleteTodo2: function (item){
this.todos2.splice(item.id, 1);
},
updateValue2: function(text){
console.log(text);
}
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s, transform 0.3s;
transform-origin: left center;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
transform: scale(0.5);
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div class="col-md-12">
<div class="graybox">
<h5>app14</h5>
<div id="app-14">
`enter code here`<div class="row">
<div class="col-md-6">
<h5> todo list using "ntodo-item" component</h5>
<p>This one show me a warning because the child cannot edit the va passed by the parent but it is working and spected</p>
<input class="form-control"
v-model="newTodoText"
v-on:keyup.enter="addNewTodo"
placeholder="Add a todo"
>
<hr>
<ul>
<li
is="ntodo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-bind:edit="todo.edit"
v-on:input="updateValue(todo, $event)"
v-on:remove="todos.splice(index, 1)"
v-on:edit="editTodo(todo)"
></li>
</ul>
</div>
<div class="col-md-6">
<h5> todo list update</h5>
<p> This one is working without any warn but I dont know how to discard changes. I dont want to create a temp var because I want to be able to edit all of them at the same time. </p>
<input v-model="newTodoText2"
v-on:keyup.enter="addNewTodo2"
placeholder="Add a todo"
class="form-control"
>
<hr>
<ul>
<transition-group name="fade" >
<li v-for="(todo2, index) in todos2":key="todo2.id">
<div id="if" class="row" v-if="todo2.edit">
<div class="col-md-7">
<input class="form-control" ref="todo2" v-model="todo2.title">
</div>
<div id="sssss" class="col-md-5">
<button class="btn btn-success roundButton" v-on:click="editTodo2(todo2)">ok</button>
</div>
</div>
<div id="else" class="row" v-else>
<div class="col-md-7">
{{todo2.title}}
</div>
<div id="ssaaas" class="col-md-5">
<button class="btn btn-danger roundButton" v-on:click="todos2.splice(index, 1)">Remove</button>
<button id="aaa" class="btn btn-default roundButton" v-on:click="editTodo2(todo2)">Edit</button>
</div>
</div>
</li>
</transition>
</ul>
</div>
</div>
</div>
</div>
</div>
.
Echoing my comment:
Create a local variable copy of your title prop and emit that variable's changes on edit. If they discard the edit just reset the local variable to the value of the title prop. Working example on CodeSandbox here.
Todo Item Component
<button class="btn btn-danger roundButton" #click="discardEdit">Discard</button>
...
data() {
return {
// our local copy
localTitle: null,
};
},
mounted() {
this.localTitle = this.title;
},
methods: {
updateValue: function() {
this.$emit("input", this.localTitle);
},
discardEdit: function() {
// just set local back to title prop value
this.localTitle = this.title;
this.$emit('edit');
},
}

v-for with dynamic keys

Very new to Vuejs 2. Have a question on how to enumerate through a dynamic set of data that has a dynamic key? Take this data for instance (this is from a 3rd party -- so unable to change data -- and shortened for readability):
{
"143": {
"account_id": 1,
"name": "Account 1",
"groups": [
{
"1610": {
"name": "Group 1610",
"meetings": [
{
"20170816": [
{
"id": 10755,
"name": "Untitled"
}
]
}
]
}
}
]
}
}
Then I have a .vue file that has a template that does this:
<div v-for="(account, accountKey) in accounts">
<div>{{ account.name }} ({{ accountKey }})</div>
<div v-for="(group, groupKey) in groups">
<div>{{ group.name }} ({{ groupKey }})</div>
<div v-for="(meeting, meetingKey) in meetings">
<div>{{ meeting.name }} ({{ meetingKey }})</div>
</div>
</div>
</div>
This doesn't render anything. There are several things I need to here, but not sure how to accomplish in Vuejs.
Need to be able to pull the key (as it's the identifier) for each of the records.
Need to be able to access the individual data on record, of course.
Anyone come across something similar that can help with?
Thanks!
That might be one of the worst data structures I've ever seen.
Here is a template that works as I think you intend.
<div v-for="(account, accountKey) in accounts">
<div>{{ account.name }} ({{ accountKey }})</div>
<div v-for="group in account.groups">
<div v-for="grp, grpKey in group">
<div>{{ grp.name }} ({{ grpKey }})</div>
<div v-for="(meeting, meetingKey) in grp.meetings">
<div v-for="mtg, mtgKey in meeting">
<div v-for="m in mtg">{{ m.name }} ({{ mtgKey }})</div>
</div>
</div>
</div>
</div>
</div>
Groups is an array of objects that have their own set of keys so you need to iterate over that, and then iterate again over each object inside the group.
Meetings is the same kind of thing, an array of objects with their own keys, but it doubles down and each of the key values is an array that... has to be iterated over again.
console.clear()
new Vue({
el: "#app",
data:{
accounts: {
"143": {
"account_id": 1,
"name": "Account 1",
"groups": [
{
"1610": {
"name": "Group 1610",
"meetings": [
{
"20170816": [
{
"id": 10755,
"name": "Untitled"
}
]
}
]
}
}
]
}
}
}
})
<script src="https://unpkg.com/vue#2.4.2"></script>
<div id="app">
<div v-for="(account, accountKey) in accounts">
<div>{{ account.name }} ({{ accountKey }})</div>
<div v-for="group in account.groups">
<div v-for="grp, grpKey in group">
<div>{{ grp.name }} ({{ grpKey }})</div>
<div v-for="(meeting, meetingKey) in grp.meetings">
<div v-for="mtg, mtgKey in meeting">
<div v-for="m in mtg">{{ m.name }} ({{ mtgKey }})</div>
</div>
</div>
</div>
</div>
</div>
</div>
It would probably be worthwhile transforming that data into a sane data structure with a computed value and iterating over the computed.