i have an api that returns some json with a list of vendors and i want to pass an array of just the names of the items in the json into a sfc vue component as a prop.
for some reason this isnt working and i dont know why
the parent component should be passing in the array of vendor names in to the child component to be used as the options for a dropdown menu
parent component:
<template>
<div>
<h1 class="title">Catalog</h1>
<dtable v-bind:tableData="products" v-bind:vendors="vendor_names"></dtable>
</div>
</template>
<script>
import axios from 'axios';
import dtable from "../components/dataTable.vue"
export default {
components: {
dtable,
},
data: () => ({
vendors: [],
vendor_names: [],
}),
methods: {
loadVendors() {
axios.get("http://127.0.0.1:8000/vendors.json")
.then(response => (this.vendors = response.data))
},
get_vendor_names() {
this.vendor_names = this.vendors.map(vname => { return vname.name })
console.log("vendor names", this.vendor_names)
},
},
mounted() {
this.loadVendors()
this.get_vendor_names()
}
}
</script>
child component:
<template>
<div class="card">
<DataTable :value="tableData" editMode="row" dataKey="id" v-model:editingRows="editingRows"
<Column field="sku" header="SKU" style="width:10%" :sortable="true">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
<Column field="name" header="Name" style="width:30%" :sortable="true">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="description" header="Description" style="width:30%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column
<Column field="brand" header="Vendors" style="width:20%" :sortable="true">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="vendors" optionValue="value" placeholder="Select a Brand">
</Dropdown>
</template>
</Column>
<Column field="price" header="Price" style="width:20%" :sortable="true">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column :rowEditor="true" style="width:10%; min-width:8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: [
'tableData',
'vendors'
],
data() {
return {
selectedProducts: null,
editingRows: [],
}
}
}
</script>
my JSON is:
[
{
"id": 1,
"name": "name1",
"description": "test"
},
{
"id": 2,
"name": "name2",
"description": "test"
},
{
"id": 3,
"name": "name3",
"description": "test"
}
]
any help is greatly appreciated
thank you to #Gabe
making it a computed property worked like a charm
You are not waiting for the loadVendors call, so when you call
get_vendor_names() the vendors array is probably still empty. I
suggest you make vendor_names a computed property, so it updates when
vendors changes.
Related
I am trying to move items from one list to another using vue draggable, but the lists are inside of a component and I can't get it to work. The items are able to move inside a list but not from a list to another.
I have got a Board component containing all the lists and a List component containing the draggable items.
This is the board component:
<template>
<div class="board">
<BoardMenu :users="this.users" :name="this.name"> </BoardMenu>
<div class="boardContent">
<Backlog></Backlog>
<div class="lists">
<List
class="list"
v-for="list in lists"
:key="list.id"
:id="list.id"
:items="list.items"
></List>
</div>
</div>
</div>
</template>
<script>
import BoardMenu from "./BoardMenu";
import Backlog from "./Backlog";
import List from "./List";
export default {
name: "UserIcon",
props: {
id: Number
},
components: {
BoardMenu,
Backlog,
List
},
data() {
return {
name: "BOARDNAME",
users: [{ name: "Bram Coenders" }, { name: "Jasper van der Zwaan" }],
lists: [
{
id: 1,
items: [
{
type: "story",
id: 1,
listId: 1
},
{
id: 2,
listId: 1
},
]
},
{ id: 2, items: [] }
],
backlog: { id: 2 }
};
},
};
</script>
And this is the List component:
<template>
<div class="list">
<div class="list-header">
<h2 id="list-name">{{ name }}</h2>
<p id="list-description">{{ description }}</p>
</div>
<draggable
v-model="items"
:list="this.id"
class="list-list"
>
<div :id="item.id" class="list-item" v-for="item in items" :key="item.id">
<div v-if="item.type == 'story'">
<Story class="story" :id="item.id"></Story>
</div>
<div v-else>
<Task class="task" :id="item.id"></Task>
</div>
</div>
</draggable>
</div>
</template>
<script>
import draggable from "vuedraggable";
import Story from "./Story.vue";
import Task from "./Task.vue";
export default {
name: "List",
components: {
Story,
Task,
draggable
},
props: {
items: []
},
data() {
return {
name: "To do",
description: "this sprint."
};
},
methods :{
newItem: function(){
console.log("test")
}
}
};
</script>
Add :options='{group: "items"}' to your draggable component or you can just try to add the attribute group="items" (if you're using Vue 2.2+)
I have built a search filter to React. The JSON file stores the name and the image of the model. There is an error like the name can be displayed on the website but the image is not read.
My code is here https://codesandbox.io/s/search-filter-in-reactjs-forked-k8nrf?file=/src/Search/index.js
import React, { Component } from "react";
import {
Input,
Card,
CardBody,
CardTitle
} from "mdbreact";
import "./style.css";
import modelList from "./models.json";
class App extends Component {
state = {
search: ""
};
renderModel = model => {
return (
<div className="col-md-3" style={{ marginTop: "20px" }}>
<Card>
<CardBody>
<p className="">
<img
src={model.image}
className={model.image}
alt={model.name}
/>
</p>
<CardTitle title={model.name}>
{model.name.substring(0, 15)}
{model.name.length > 15 && "..."}
</CardTitle>
</CardBody>
</Card>
</div>
);
};
onchange = e => {
this.setState({ search: e.target.value });
};
render() {
const { search } = this.state;
const filteredModels = modelList.filter(model => {
return model.name.toLowerCase().indexOf(search.toLowerCase()) !== -1;
});
return (
<div className="flyout">
<main style={{ marginTop: "4rem" }}>
<div className="container">
<div className="row">
<div className="col">
<Input
label="Search Model"
icon="search"
onChange={this.onchange}
/>
</div>
<div className="col" />
</div>
<div className="row">
{filteredModels.map(model => {
return this.renderModel(model);
})}
</div>
</div>
</main>
</div>
);
}
}
export default App;
Can someone stop by to help me display the image on JSON on the website? Thanks a lot
Just move the images to your public folder, so that they are not all loaded on startup but only if needed.
You can just move the whole folder like it is.
<img src will automatically search for images in the public folder, if you add a / in front of the url:
[
{
"name": "Sample 1",
"image": "/asset/crab-nebuala.png"
},
{
"name": "Sample 2",
"image": "/asset/crab-nebula.png"
},
{
"name": "Sample 3",
"image": "/asset/ghost-nebua.png"
},
{
"name": "Sample 4",
"image": "/asset/sample-nebula-2.png"
},
{
"name": "Sample 5",
"image": "/asset/sample-nebula.png"
}
]
That's all you need. Here is your updated sandbox.
How would it work if I want to commit the input value and the selected options in the Vuex store (without the "label" string so that the object I send matches my Vuex store object) ?
Template
<div v-for="(section, indexSections) in sections" :key="indexSections">
<div v-for="(item, indexItem) in section" :key="indexItem">
<div>
<select
v-model="sections[indexSection][indexItem].options"
:options="selectOptions"
></select>
<b-input
type="text"
v-model="sections[indexSection][indexItem].sectionItem"
></b-input>
<b-button #click="removeItem({section,item})"/>
</div>
</div>
<div">
<b-button #click="addNewItem(section)"/>
<b-button #click="addNewSection"/>
</div>
</div>
Data
selectOptions: [
{
options: { option1: true, option2: true },
label: "First"
},
{
options: { option1: false, option2: true },
label: "Second"
}
]
Computed
Computed: {
sections: {
get() {
return this.$store.state.sections;
}
}
Store
sections: [
[{
sectionItem: "",
options: {
strict: true,
includes: true
}
}]
],
You cannot use v-model in order to change the Vuex state, that is what the mutations are for.
v-model is just syntatic sugar and handles the event and updating of values. You have to implement v-on:change yourself and call a Vuex mutation to set the selected option.
Your selectOptions array looks unusual. Usually you just have a label and a value for options. The value is the selected value when the user selects an option.
<template>
<div>
<select #change="onChange">
<option v-for="option in selectOptions" :value="option.value">
{{ option.label }}
</option>
</select>
</div>
</template>
<script>
export default {
data () {
return {
selectOptions: [
//...
],
}
},
methods: {
onChange(event) {
this.$store.commit('setSelectedOption', event.target.value);
},
},
};
</script>
I generate a JSON with a lot of nested data, one of those properties called 'value' inside 'operations' is used in the v-model of every input of a dynamic generated html table. Initially that property is set to 0 and the input is set with that value but when I change the value in the input it doesn't reflect in the json
The JSON
[
{
"establishment_id":1,
"values":[
{
"capa_id":"A",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"B",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
{
"capa_id":"C",
"operations":[
{
"operation_id":1,
"value":0
},
{
"operation_id":2,
"value":0
},
{
"operation_id":3,
"value":0
},
{
"operation_id":4,
"value":0
}
]
},
]
},
]
The component
Establishments, Operations and CAPA are objects taken from an API via Axios, those data are used to generate the table and the json for the input data
<v-expansion-panels multiple focusable popout class="py-5">
<v-expansion-panel class="expandable" v-for="(establishment, establishmentIndex) in establishments">
<v-expansion-panel-header class="exp_estb">
</v-expansion-panel-header>
<v-expansion-panel-content class="ma-0 pa-0">
<v-row no-gutters>
<v-col cols="12">
<form>
<v-simple-table>
<template>
<thead>
<tr>
<th scope="col">ESTABLECIMIENTO</th>
<th v-for="(operation, index) in operations" scope="col">
{{ operation.description }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(capa, capaIndex) in capas">
<td>{{capa.name}}</td>
<td v-for="(operation, operationIndex) in operations">
<span>{{ operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value }}</span>
<v-row class="pr-5">
<v-col cols="12" class="mr-2 pr-5">
<v-text-field v-model="operation_data[establishmentIndex].values[capaIndex].operations[operationIndex].value" label="" color="#7F53DD"></v-text-field>
</v-col>
</v-row>
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</form>
</v-col>
</v-row>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
Computed
computed:
{
operation_data: function()
{
let operation_data=[]
let operationsWithContent=[]
let capasWithOperations=[]
var establishments = Object.values(this.establishments)
var capas = Object.values(this.capas)
var operations = Object.values(this.operations)
operations.forEach(operation => operationsWithContent.push({ operation_id:operation.id, value: 0 }))
capas.forEach(capa => capasWithOperations.push({ capa_id:capa.id, operations:operationsWithContent }))
establishments.forEach( establishment => operation_data.push({ id:establishment.id, values:capasWithOperations}) )
return operation_data
}
},
Is there a specific reason you need a computed here? It seems more logical to fetch your data using a method and saving that result in a variable. Then you can assign the variable to the v-model like you already did in your example and it should work out of the box.
data() {
return {
operation_data: null
}
},
mounted() {
this.fetchData();
},
methods: {
fetchData() {
// Get your data here with axios
this.operation_data = resultOfAxios;
}
}
For your question on why the data doesn't reflect back:
A computed is initially just a getter. You have to manually add a setter for the computed for it to be able to update data.
I'm attempting to develop a login page that operates off of the following .json file: https://api.myjson.com/bins/fyufr
I implemented an output to the console, which displays the results of the json file. The Issue I'm encountering, when I click the button on the form after the username and password are entered, the login page fails to direct the user to the landing page. The submit button login is written in the function onSubmit
This is the code:
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import './Login.css';
const divStyle = {
margin: '40px',
};
const divStyleI = {
width: '600px',
};
class Login extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
componentWillMount() {
fetch('https://api.myjson.com/bins/fyufr', {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
}) /*end fetch */
.then(results => results.json())
.then(data => this.setState({ data: data })
)}
onSubmit() {
if (this.state.username.value == '{userName}' && this.state.password.value == '{password}' ){
this.state.history.push("/memberinfo");
}
}
//render component
render() {
console.log(this.state.data);
return (
<div style={divStyle}>
<h2>Member Login</h2>
<div style={divStyleI}>
<form>
<div className="form-group">
<label for="username">User Name:</label>
<input
className="form-control"
type="text"
placeholder="Enter User Name"
name="username"
/>
</div>
<div className="form-group">
<label for="pwd">Password:</label>
<input
className="form-control"
type="password"
placeholder="Enter your password"
name="password"
/>
</div>
<div>
<input
className="btn btn-primary"
type="submit"
value="submit"
onClick={() => this.onSubmit()}
/>
</div>
</form>
</div>
</div>
);
}
}
export default withRouter(Login);
this is the json sample w/ test data:
[
{
"userName": "aknightt",
"firstName": "Adam",
"lastName": "Knight",
"password": "password1",
"token": "ayJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ8.ayJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiR3JlZyIsInVuaXF1ZV9uYW1lIjoiZ2dyYWZmIiwibmJmIjoxNTI1MTIyOTQ5LCJleHAiOjE1MjUyMDkzNDl9.BzTaSSODX1yreo14dx_N-ucPnDgGbbJXusGLnZhWd9A"
},
{
"userName": "ckeaton",
"firstName": "Calvin",
"lastName": "Keaton",
"password": "password2",
"token": "KyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ8.hyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiR3JlZyIsInVuaXF1ZV9uYW1lIjoiZ2dyYWZmIiwibmJmIjoxNTI1MTIyOTQ5LCJleHAiOjE1MjUyMDkzNDl9.BzTaSSODX1yreo14dx_N-ucPnDgGbbJXusGLnZhWd9C"
},
{
"userName": "esprite",
"firstName": "Emma",
"lastName": "Sprite",
"password": "temp2",
"token": "LyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ8.jyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiR3JlZyIsInVuaXF1ZV9uYW1lIjoiZ2dyYWZmIiwibmJmIjoxNTI1MTIyOTQ5LCJleHAiOjE1MjUyMDkzNDl9.BzTaSSODX1yreo14dx_N-ucPnDgGbbJXusGLnZhWd9C"
}
]
could I get some guidance as to what I'm doing wrong? ...Thanks in Advance