Hi i am try to show json file result with vue.js the target is that result will be showed on value.
this is my code:
data () {
return {
fetchData: function () {
var self = this;
self .$http.get( "/api/casetotalactivation", function( data ) {
self.items = data;
});
},
statsCards: [
{
type: 'warning',
icon: 'ti-server',
title: 'Cases',
value: this.items,
footerText: 'Updated now',
footerIcon: 'ti-reload'
}
],
use this code:
<div id="vueapp">
<textarea v-model="jsonstr" rows="8" cols="40"></textarea>
<pre>{{ jsonstr | pretty }}</pre>
</div>
and JS:
new Vue({
el: '#vueapp',
data: {
jsonstr: '{"id":1,"name":"A green door","price":12.50,"tags":["home","green"]}'
},
filters: {
pretty: function(value) {
return JSON.stringify(JSON.parse(value), null, 2);
}
}
})
HTML and JS have this built into the language. Try...
<pre>{{ yourObject }}</pre>
This gives the default indent, to specify a custom indent provide it as the third argument to JSON.stringify(...).
// replace 2 with '\t' to do tab indentation
<pre>{{ JSON.stringify(yourObject, null, 2) }}</pre>
If you're outside of Vue then using some combo of the above snipped will do.
just use <pre>
<pre>{{json}}</pre>
The following code shows how to show json result with Vue 3
Display a stringified json object inside a <textarea> using v-model
Display object properties with <li v-for="">
<template>
<div class="hello">
<textarea v-model="listDataString" rows="20" cols="80"></textarea>
<ul id="items">
<li v-for="(item, index) in listData" :key="index">
{{ `${item.text} [${item.id}]` }}
</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "RenderList",
props: {
msg: String,
},
data() {
return {
listDataString: String,
listData: [], // placeholder
};
},
mounted() {
axios
.get("=== [API_ENDPOINT] ===")
.then((response) => {
this.listDataString = JSON.stringify(response.data, null, "\t");
this.listData = response.data;
console.log(this.listDataString);
return response; // multiline arrow function must return
});
},
};
</script>
If the /api is only on the dev server you can create a vue.config.js file in the app root folder.
module.exports = {
devServer: {
before: function(app, server) {
app.get('/api', function(req, res) {
const result = [{
type: 'warning',
icon: 'ti-server',
title: 'Cases',
value: this.items,
footerText: 'Updated now',
footerIcon: 'ti-reload'}];
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(result));
});
}
}
}
With this files when I run npm run serve, I get the json object when navigating to /api and my regular app otherwise.
Just use this:
<pre v-html="JSON.stringify(objectJs, null, 2)"></pre>
Related
enter image description hereI am making an app in Nuxt and vue using storyblok as my CMS. However, I have been receiving errors when trying to link the storyblok array to my arrays called in my template using v-for.
Here is the template:
<template>
<div>
<!-- instance header -->
<InstanceHeader title="Books" />
<div class="pageContainer">
<div class="booksInfoPost">
<div class="booksInfoPost__subHeader"><h3>Top Books</h3></div>
<div class="booksInfoPost__topBooks">
<BooksInfoPostTop
v-for="book in books"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
<div class="booksInfoPost__subHeader"><h3>Book Titles</h3></div>
<BooksInfoPost
v-for="book in posts"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
</div>
Here is my script:
export default {
components: {
InstanceHeader,
BooksInfoPostTop,
BookTitles,
BooksInfoPost
},
data() {
/* return {
books: [],
posts: []
} */
},
async asyncData(context) {
return {
bookTitles: context.app.$storyapi
.get("cdn/stories", { version: "draft", starts_with: 'books/book-titles'})
.then(response => {
console.log(response);
return {
posts: response.data.stories.map(bp => {
return {
id: bp.slug,
bookCover: bp.content.bookCover,
title: bp.content.title,
author: bp.content.author
};
}),
}
}),
topBooks: context.app.$storyapi
.get("cdn/stories", { version: "draft", starts_with: 'books/top-books'})
.then(response => {
console.log(response);
return {
books: response.data.stories.map(b => {
return {
id: b.slug,
bookCover: b.content.bookCover,
title: b.content.title,
author: b.content.author
};
}),
}
})
}
}
}
I noticed this error more when I tried calling two APIs from storyblok. When I called one API call I did not see this error. I have also tried using Axios but I am getting errors using that method as well. I am not the most experienced developer and If anyone can help I'll appreciate it. Thanks
export default {
components: {
InstanceHeader,
BooksInfoPostTop,
BookTitles,
BooksInfoPost
},
async asyncData(context) {
const result = {};
const mapBooks = b => {
return {
id: b.slug,
bookCover: b.content.bookCover,
title: b.content.title,
author: b.content.author
};
};
const { data } = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/book-titles'
});
result.posts = data.stories.map(mapBooks);
const result = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/top-books'
});
result.books = result.data.stories.map(mapBooks);
return result; // it has right property names {books:[], posts:[]}
}
}
Well as you mentioned in the comment it was a little mess before. So i tidied it up. The idea is that you need direct property names instead of nested objects. This way it should work, if it is not working check the network tab for the errors.
I'm using a Vue Multiselect instance with 2 functions (one basically hits the database for an autocomplete function, which works. The other is adding a new one that isn't in the database)
So say 'Tag One' is in the database, if I type that and it shows then hitting enter or selecting will save it to the tags (multiselect with tagging enabled). However, if I type 'Tag Three' which isn't in the database and I hit enter or select, it just disappears and doesn't add to the tags or call the axios function in my addTag method.
What exactly am I doing wrong?
<script src="https://unpkg.com/vue-multiselect#2.1.0"></script>
<script src="https://unpkg.com/#johmun/vue-tags-input/dist/vue-tags-input.js"></script>
<div id="tagApp">
<multiselect
label="tag_data"
track-by="campaign_tag_id"
v-model="value"
:options="options"
:multiple="true"
:taggable="true"
#tag="addTag"
#search-change="val => read(val)"
:preselect-first="false"
:close-on-select="false"
:clear-on-select="true"
:preserve-search="true"
tag-placeholder="Add this as new tag"
placeholder="Search or add a tag"
></multiselect>
</div>
new Vue({
components: {
Multiselect: window.VueMultiselect.default
},
el: "#tagApp",
data() {
return{
value: [],
loading: false,
options: []
}
},
methods: {
read: function(val){
if (val) {
this.loading = true;
this.options = [];
const self = this;
console.log(val);
axios.get('search',{params: {query: val}})
.then(function (response) {
self.options = response.data;
console.log(response.data);
});
} else {
this.options = [];
}
},
addTag(newTag) {
const tag = {
tag_data: newTag,
};
const campaign_id = document.querySelector("input[name=campaign_id]").value;
this.options.push(tag);
this.value.push(tag);
axios.post('tags/save',{
tag_data: newTag,
})
.then(function (response){
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
})
I don’t think you are doing anything wrong, I just don’t think the component supports what you want to do.
But, what you could do is always add the search term to the options array if it isn’t there already. Putting the below in the axios callback could be all you need.
self.options = response.data;
self.options.push(val)
Now you could slice it to the front, or keep it pushed at the end, and code to prevent duplicates etc.
<li v-for="people in projectData.employees" :key="people._id">
<b-img :src="colleagueImages(people)"
</li>
async colleagueImages(people) {
console.log(people); // => max#stackoverflow.com
let profileImage = await axios.get("http://myapilink.com/image?id=" + people + "&s=200&def=avatar", {
headers: {
'accept': 'image/jpeg'
}
});
console.log(profileImage);
return 'data:image/jpeg;base64,' + btoa(
new Uint8Array(profileImage.data)
.reduce((data, byte) => data + String.fromCharCode(byte), '')
);
}
The console.log(profileImage) returns the following:
The API I am using is returning a Base64 Image.
With my current code I only get the following error in my browser console:
[Vue warn]: Invalid prop: type check failed for prop "src". Expected String, got Promise.
Since you don't have all the data you need to render in the first place, you have to change attributes afterwards. First, you need to use Vue components for your items, so your "src" attribute will be reactive; second, you start the requests for your items after you rendered your app. Please see this mockup.
Vue.component('todo-item', {
template: `
<li>
<label>
<input type="checkbox"
v-on:change="toggle()"
v-bind:checked="done">
<del v-if="done">
{{ text }}
</del>
<span v-else>
{{ text }}
</span>
<span v-if="like">
♥ {{like}}
</span>
</label>
</li>
`,
props: ['id', 'text', 'done', 'like'],
methods: {
toggle: function(){
this.done = !this.done
}
}
})
let todos = [
{id: 0, text: "Learn JavaScript", done: false, like: null },
{id: 1, text: "Learn Vue", done: false, like: null },
{id: 2, text: "Play around in JSFiddle", done: true, like: null },
{id: 3, text: "Build something awesome", done: true, like: null }
]
const v = new Vue({
el: "#app",
data: {
todos: todos
}
})
todos.forEach((item) => {
// This is just a mock for an actual network request
window.setTimeout(() => {
item.like = Math.ceil(Math.random() * 100)
}, Math.random() * 2000)
})
https://jsfiddle.net/willywongi/gsLqda2y/20/
In this example I have the basic todo-list app with a fake "like" count for each item, which is calculated asynchronously. After setting up my app, I wait for the "like" attribute values (in my example I just wait a random value of milliseconds).
I tried to use the el-autocomplete tag with the simplest version: an Array returned by the callback function (JSFiddle version).
Vue.component('button-counter', {
data: function() {
return {
selectdusers: [],
user: ''
}
},
template: '<el-container> <el-container style="margin-left: 15px; width: 150px"> <el-autocomplete class="inline-input" v-model="user" :fetch-suggestions="filterUsers" placeholder="add user" #select="handleSelect" ></el-autocomplete> <el-button type="info" icon="el-icon-plus" click="addUser(user)">Add</el-button> </el-container> </el-container>',
methods: {
addUser(user) {
this.selectedUsers.push(user)
this.user = ''
},
filterUsers(user, cb) {
console.log(user)
cb(['qqq', 'zzz'])
//return this.allusers.filter(x => _.includes(x.f+x.t, user))
},
handleSelect() {}
},
})
new Vue({
el: '#components-demo'
})
#import url("//unpkg.com/element-ui#2.4.8/lib/theme-chalk/index.css");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.7/index.js"></script>
<div id="components-demo">
<button-counter></button-counter>
</div>
The suggestion box is visually empty, depite DevTools showing the expected elements in <ElAutocompleteSuggestions> → data → suggestions
For using Array instead of Object, you can use slot in autocomplete block
<el-autocomplete ...>
<template slot-scope="{ item }">
<div class="item">{{ item }}</div>
</template>
</el-autocomplete>
What needs to be passed via the callback is an Object which must have a property called value. This property holds what is displayed as the suggestion.
For the example above:
filterUsers(user, cb) {
console.log(user)
cb([{'value': 'qqq', 'whatever': 'djhjfh'}, {'value': 'zzz', 'whatever': 'uiuiiu'}])
},
I'm building a key-command resource and giving VueJS a whirl while doing so. I'm a newbie but am gaining the grasp of things (slowly...).
I want to be able to search in a global search form for key commands I'm defining as actions within sections of commands (see data example below). I would like to search through all the actions to show only those that match the search criteria.
My HTML is below:
<div id="commands">
<input v-model="searchQuery" />
<div class="commands-section" v-for="item in sectionsSearched"
:key="item.id">
<h3>{{ item.section }}</h3>
<div class="commands-row" v-for="command in item.command" :key="command.action">
{{ command.action }}
</div>
</div>
</div>
My main Vue instance looks like this:
import Vue from 'vue/dist/vue.esm'
import { commands } from './data.js'
document.addEventListener('DOMContentLoaded', () => {
const element = document.getElementById("commands")
if (element != null) {
const app = new Vue({
el: element,
data: {
searchQuery: '',
commands: commands
},
computed: {
sectionsSearched() {
var self = this;
return this.commands.filter((c) => {
return c.command.filter((item) => {
console.log(item.action)
return item.action.indexOf(self.searchQuery) > -1;
});
});
},
}
});
}
});
And finally the data structure in data.js
const commands = [
{
section: "first section",
command: [
{ action: '1' },
{ action: '2' },
{ action: '3' },
],
},
{
section: "second section",
command: [
{ action: 'A' },
{ action: 'B' },
{ action: 'C' },
]
},
]
export { commands };
I'm able to output the commands using the console.log(item.action) snippet you see in the computed method called sectionsSearched.
I see no errors in the browser and the data renders correctly.
I cannot however filter by searching in real-time. I'm nearly positive it's a combination of my data structure + the computed method. Can anyone shed some insight as to what I'm doing wrong here?
I'd ideally like to keep the data as is because it's important to be sectioned off.
I'm a Rails guy who is new to this stuff so any and all feedback is welcome.
Thanks!
EDIT
I've tried the proposed solutions below but keep getting undefined in any query I pass. The functionality seems to work in most cases for something like this:
sectionsSearched() {
return this.commands.filter((c) => {
return c.command.filter((item) => {
return item.action.indexOf(this.searchQuery) > -1;
}).length > 0;
});
},
But alas nothing actually comes back. I'm scratching my head hard.
There is a issue in your sectionsSearched as it is returning the array of just commands.
See this one
sectionsSearched() {
return this.commands.reduce((r, e) => {
const command = e.command.filter(item => item.action.indexOf(this.searchQuery) > -1);
const section = e.section;
r.push({
section,
command
});
}, []);
}
const commands = [
{
section: "first section",
command: [
{ action: '1' },
{ action: '2' },
{ action: '3' },
],
},
{
section: "second section",
command: [
{ action: 'A' },
{ action: 'B' },
{ action: 'C' },
]
},
]
const element = document.getElementById("commands")
if (element != null) {
const app = new Vue({
el: element,
data: {
searchQuery: '',
commands: commands
},
computed: {
sectionsSearched() {
var self = this;
return this.commands.filter((c) => {
// the code below return an array, not a boolean
// make this.commands.filter() not work
// return c.command.filter((item) => {
// return item.action.indexOf(self.searchQuery) > -1;
// });
// to find whether there has command action equal to searchQuery
return c.command.find(item => item.action === self.searchQuery);
});
},
}
});
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="commands">
<input v-model="searchQuery" />
<div class="commands-section" v-for="item in sectionsSearched"
:key="item.id">
<h3>{{ item.section }}</h3>
<div class="commands-row" v-for="command in item.command" :key="command.action">
{{ command.action }}
</div>
</div>
</div>
Is that work as you wish ?
sectionsSearched() {
return this.commands.filter((c) => {
return c.command.filter((item) => {
return item.action.indexOf(this.searchQuery) > -1;
}).length > 0;
});
},
}
since filter will always return an array(empty or not) which value always is true.