everyone. Sorry, for my dumb question, but I've tried a lot to do.
What I want to do is pass result of getUser() function to my Home.vue app.
But first, I tried to pass simple variable 'counter' using props:
main.js
import Vue from 'vue';
import App from './App';
import router from './router';
import store from './store';
Vue.config.productionTip = false;
export default new Vue({
router,
store,
el: '#app',
props: { 'counter': 1 },
template: '<app v-bind:counter="counter" />',
components: { App },
created () {
// fetch the data when the view is created and the data is
// already being observed
this.getUser()
},
methods: {
getUser() {
fetch('/api/auth/user/user/')
.then(response => response.json())
.then(data => console.log(data));
}
},
});
Home.vue
<template lang="pug">
#app
.card(v-for="profile in profiles")
.card-header
button.btn.btn-clear.float-right(#click="deleteProfile(profile)")
.card-title {{ profile.user }}
.card-body {{ profile.phone_number }}
.card-body {{ profile.address }}
.card-body {{ counter }}
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'profile-list',
computed: mapGetters(['profiles']),
props: ['counter'],
methods: {
deleteProfile (profile) {
// Вызываем действие `deleteNote` из нашего хранилища, которое
// попытается удалить заметку из нашех базы данных, отправив запрос к API
this.$store.dispatch('deleteProfile', profile)
}
},
beforeMount () {
// Перед тем как загрузить страницу, нам нужно получить список всех
// имеющихся заметок. Для этого мы вызываем действие `getNotes` из
// нашего хранилища
this.$store.dispatch('getProfile')
},
}
What I want to do is print 'counter' under profile.address but this doesn't work.
Thank you.
I don't see any initialisation of counter. Just change your code from
props: { 'counter': 1 } to
data () {return { 'counter': 1 }}
Learn more: https://v3.vuejs.org/api/options-data.html#data
Related
I'm quite new with Vue and Vuex, actually I'm just doing a little app which display events, and you can access to each card event and see details through the card's ID. I passed all the code to vuex Store, and I'm having problems rendering individual cards, based on the error I understand that the problem is accessing the ID, but I'm console logging the props.id, and you can see the result in console:123 (I clicked on the first card and that's the correct ID)
So here's the EventList Component:
once I click on one of 'em, I get this console error:
Here is the code:
EventDetails component:
<template>
<div class="event-card">
<h2>You are on {{ $route.params.props.id }}</h2>
<span>#{{ event.time }} on {{ event.date }}</span>
<h4>{{ event.title }}</h4>
<p>{{ event.description }}</p>
</div>
</template>
<script>
import store from "#/store";
import { computed } from "#vue/reactivity";
import { onBeforeMount, onMounted, reactive, ref, toRefs } from "vue";
import { useStore } from "vuex";
export default {
name: "EventDetails",
props: ["id", "modelValue"],
setup(props) {
const state = reactive({
events: [],
event: {},
});
const message = ref("AsapRocky");
console.log(props.id)
onMounted(() => {
store.dispatch('fetchEvent', props.id)
});
const event = computed(() => {
return store.state.event;
});
return {
event,
message,
...toRefs(state),
};
},
};
</script>
store code:
import { createStore } from 'vuex'
import apiClient from '../services/EventService';
export default createStore({
state: {
user: 'TommyDemian',
events: [],
event: {}
},
mutations: {
SET_EVENTS(state, events){
state.events = events;
},
SET_EVENT(state, event) {
state.event = event;
}
},
actions: {
fetchEvents({ commit }){
apiClient
.getEvents()
.then((response) => {
commit("SET_EVENTS", response.data)
})
.catch((error) => {
console.log(error);
});
},
fetchEvent({ commit }, id){
apiClient.getEvent(id)
.then((response) => {
commit("SET_EVENT", response.data)
})
.catch((error) => {
console.log(error);
});
}
},
getters: {
},
modules: {
}
})
The stacktrace indicates the problematic reference to id is actually in {{ $route.params.props.id }} from your template.
I assume you were trying to access the component's id prop, which would not be in the route parameters:
<!-- <h2>You are on {{ $route.params.props.id }}</h2> --> ❌
<h2>You are on {{ id }}</h2> ✅
Original question:
vuex shared state in chrome extension
I have the following setup in a chrome extension;
A content script that needs to write to a vuex store
A background script that initializes that store
And a popup script that renders stuff from the store (received from the content script)
store.js
import Vue from "vue";
import Vuex from "vuex";
import "es6-promise/auto";
import createMutationsSharer from "vuex-shared-mutations";
import dummyData from "./dummyData";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
chromePagesState: {
allSections: [],
},
},
mutations: {
setChromePagesState(state, value) {
state.chromePagesState = value;
},
addWhiteListedItem(state, item) {
state.chromePagesState.allSections[0].itemSectionCategory[0].tasks.splice(
0,
0,
item
);
},
},
actions: {
// init from local storage
async loadChromePagesState({ commit }) {
const json = await getStorageValue("inventoryData");
commit(
"setChromePagesState",
Object.keys(json).length === 0 && json.constructor === Object
? dummyData
: JSON.parse(JSON.stringify(json))
);
},
// send message to background script to call init (shortened)
async loadChromePagesStateBrowser({ commit }) {
browser.runtime
.sendMessage({ type: "storeinit", key: "chromePagesState" })
.then(async (chromePagesState) => {
const json = await getStorageValue("inventoryData");
commit(
"setChromePagesState",
Object.keys(json).length === 0 && json.constructor === Object
? dummyData
: JSON.parse(JSON.stringify(json))
);
});
},
},
// stuff from vuex-shared-mutations
plugins: [
createMutationsSharer({
predicate: [
"addWhiteListedItem",
"loadChromePagesState",
"loadChromePagesStateBrowser",
],
}),
],
});
The content script calls store from a vue component:
index.js
import store from "../popup/firstpage/store";
new Vue({
el: overlayContainer,
store,
render: (h) => h(Overlay, { props: { isPopUp: isPopUp } }),
});
Overlay.vue
<script>
import { mapState, mapMutations } from "vuex";
export default {
props: ["isPopUp"],
data() {
return {
};
},
computed: mapState(["chromePagesState"]),
methods: {
...mapMutations(["addWhiteListedItem"]),
// this gets called in the template
addToWhiteList() {
let newItem = initNewItemWithWebPageData();
this.addWhiteListedItem(newItem);
},
},
}
</script>
The background script receives a message and calls a mutation on the store:
background.js
import store from "../content/popup/firstpage/store";
browser.runtime.onMessage.addListener((message, sender) => {
if (message.type === "storeinit") {
store.dispatch("loadChromePagesState");
return Promise.resolve(store.state[message.key]);
}
});
Upon opening popup.js, a store mutation is called that sends a message to background.js that calls another mutation in the store:
popup.js
import store from "./firstpage/store";
export function showPopup() {
const popupContainer = document.createElement("div");
new Vue({
el: popupContainer,
store,
render: (h) => h(App),
created() {
console.log("Calling store dispatch from popup");
this.$store.dispatch("loadChromePagesStateBrowser");
},
});
}
Where App.vue is
<template>
<div id="app">
<OtherComponent />
</div>
</template>
<script>
import { mapActions } from "vuex";
import OtherComponent from "./components/ChromePage.vue";
export default {
name: "App",
OtherComponent: {
VueTabsChrome,
},
methods: {
...mapActions(["loadChromePagesState"]),
},
mounted() {
// once fully mounted we load data
// this is important for a watcher in ChromePage component
console.log("App.vue mounted");
// this.loadChromePagesState();
},
};
</script>
Intuitively export default new creates a new instance on every import hence the not being in sync across scripts (since the stores are different objects).
How can the same store be initialized once and used across multiple entry points?
popup.js is opened when the user clicks the extension icon:
(in this case clicks "new tab").
So I have added a second bus to my code that runs on create, but no matter in which order I call the Busses the second bus (eventBus2) is never called and then returns no data. By printing some console logs I get the feeling that that eventBus2.$on is never executed. Is there some Vue rule that I'm not aware of, any suggestions?
Item.vue
<template>
<div>
<table>
<tr
v-for="item in info"
:key="item.id"
#click="editThisItem(item.id)"
>
<td>{{ item.name}}</td>
<td>{{ item.number}}</td>
<td>{{ item.size}}</td>
</tr>
</table>
</div>
</template>
<script>
import Something from "./Something.vue";
import axios from "axios";
import { eventBus } from "../main";
import { eventBus2 } from "../main";
export default {
components: { Something },
name: "Item",
data() {
return {
selected_item_id: 0,
info: null,
};
},
methods: {
editThisItem(bolt) {
this.selected_item_id = bolt;
eventBus2.$emit("itemWasSelected", this.selected_item_id);
eventBus.$emit("newTabWasAdded", "edit-item");
},
},
mounted() {
axios
.get("http://localhost:8080/items")
.then((response) => (this.info = response.data._embedded.artikli));
},
};
</script>
EditItem.vue
<script>
import Something from "./Something.vue";
import axios from "axios";
import { eventBus2 } from "../main";
export default {
components: { Something},
name: "Edit-item",
data() {
return {
info: null,
select_number: 0,
select_name: "",
selected_item_id: -1,
priv_item: {
id: 0,
size: "big"
},
};
},
mounted() {
if (this.selected_item_id != -1) {
axios
.get("http://localhost:8080/items/" + this.selected_item_id)
.then((response) => (this.priv_item = response.data));
}
},
created() {
eventBus2.$on("itemWasSelected", (data) => {
this.selected_item_id = data;
console.log(" + " + data);
//this console log does not even print the "+", the data is empty
});
console.log(this.selected_item_id);
},
};
</script>
main.js
export const eventBus = new Vue();
export const eventBus2 = new Vue();
you're expecting itemWasSelected and emitting WasSelected they should be the same.
PD: that can be done in one line.
import { eventBus } from "../main";
import { eventBus2 } from "../main";
import { eventBus, eventBus2 } from "../main";
HelloWorld.vue
import axios from "axios";
export const router = () => axios.get("https://fakestoreapi.com/products");
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`/${item.id}`"
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
<script>
import { router } from "./router";
export default {
name: "HelloWorld",
components: {},
data() {
return {
items: [],
};
},
mounted() {
router().then((r) => {
this.items = r.data;
});
},
};
</script>
User.vue
import axios from "axios";
export const routerid = (itemId) =>
axios.get("https://fakestoreapi.com/products/" + itemId);
<template>
<div>
<div v-if="item">
<h1>Price: {{ item.price }}</h1>
</div>
<tabs />
</div>
</template>
<script>
import { routerid } from "./routerid";
import tabs from "./tabs";
export default {
name: "User",
components: {
tabs,
},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
routeId() {
return this.$route.params.id;
},
},
watch: {
routeId() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.routeId);
if (!this.routeId) return; // no ID, leave early
routerid(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
tabs.vue
import axios from "axios";
export const tabsandcontent = async (itemId) =>
await axios.get("https://fakestoreapi.com/products?limit=" + itemId);
<template>
<div>
<div v-if="item">
<h1>description: {{ item.description }}</h1>
</div>
</div>
</template>
<script>
import { tabsandcontent } from "./tabsandcontent";
export default {
name: "User",
components: {},
data() {
return {
item: null,
};
},
mounted() {
this.loadData();
},
computed: {
tabsandcontent() {
return this.$route.params.id;
},
},
watch: {
tabsandcontent() {
console.log("Reload (route change)");
this.loadData();
}, //reload when route id changes
},
methods: {
loadData() {
console.log("Reloading, ID", this.tabsandcontent);
if (!this.tabsandcontent) return; // no ID, leave early
tabsandcontent(this.$route.params.id).then((item) => {
this.item = item.data;
});
},
},
};
</script>
main.js
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import User from "./components/User";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{
path: "/HelloWorld",
name: "HelloWorld",
component: HelloWorld,
children: [{ path: ":id", name: "User", component: User }]
}
]
});
Vue.config.productionTip = false;
new Vue({
router,
render: (h) => h(App)
}).$mount("#app");
code:- https://codesandbox.io/s/combined-logic-api-forked-41lh0f?file=/src/main.js
can you please answer this, In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting... because in my project path:'/' indicates login page??? In this scenario what changes, i need to make, to make logic work
also where is the relation between path:'/' and api call??
You have same name for the variables in tabs component (In watch and computed). And In tabsandcontent.js, you have missed to fetch description for the specific item as performed in routerId.js.
Have a look at modified version which is working as you expected.
https://codesandbox.io/embed/combined-logic-api-forked-ji5oh4?fontsize=14&hidenavigation=1&theme=dark
First thing first, I want you to know that I don't understand what are you asking for. But I'm going to try to answer.
Your first question:
In main.js routing I changed from path: "/" to path: "/HelloWorld" then all of sudden output not reflecting.
Yes, you will not see your HelloWorld.vue component. You can see your page however if you type <your-url>/HelloWorld. Usually the / path is used for something like "Home" page.
However, I've tried checking out your codesandbox. And take a look at your HelloWorld.vue component.
I think you are confused because when you changed the path from / to /HelloWorld apart from the HelloWorld.vue not showing up. It somehow broken the link which causes the API in tabs.vue not functioning.
If that's the case, you just have to simply add HelloWorld/${item.id} in tabs.vue,
<template>
<div>
<div v-for="item in items" :key="item.id">
<b> id: {{ item.id }}</b>
<router-link
:to="`HelloWorld/${item.id}`" // --> Notice this line
>
{{ item.title }}
</router-link>
</div><!-- end v-for -->
<router-view></router-view>
</div>
</template>
This however, isn't a common thing to do routing. You should add your App URLs to main.js. Which also isn't common, but I'm assuming this is just a little reproduction code you made for StackOverflow.
Here are my CodeSandbox edits.
https://codesandbox.io/s/combined-logic-api-forked-jttt8p
I will update the answer again later, I'm still not on my personal laptop.
I'm trying to use vue-async-data to fetch data asynchronously before rendering my Vue component, but I'm having no success. I'm not getting any erros, but it simply doesn't work.
Here's my main.js code:
import Vue from 'vue'
import VueAsyncData from 'vue-async-data'
import router from './router'
import App from './App.vue'
Vue.use(VueAsyncData)
new Vue({
el: '#app',
router,
template: '<App/>',
components: { App }
})
And here's my App.vue code:
<template>
<div>
{{ msg }}
<navigation wait-for="async-data"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
msg: 'not loaded yet...'
}
},
asyncData: function (resolve, reject) {
// load data and call resolve(data)
// or call reject(reason) if something goes wrong
setTimeout(function () {
// this will call `vm.$set('msg', 'hi')` for you
resolve({
msg: 'hi'
})
}, 1000)
}
}
</script>
The msg value doesn't change at any moment, but the component is still rendered.
Am I missing somenthing?
As Bert Evans stated, vue-async-data doesn't work with Vue 2.0.
I used vue-router and the created function to achieve what I needed (as suggested in: https://router.vuejs.org/en/advanced/data-fetching.html.
<template>
<div>
<div class="loading" v-if="loading">
Loading...
</div>
<div v-if="error" class="error">
{{ error }}
</div>
<navigation v-if="currentUser"></navigation>
</div>
</template>
<script>
import Navigation from './components/Navigation.vue'
export default {
name: 'app',
components: {
Navigation
},
data: function() {
return {
loading: true,
error: false,
currentUser: null
}
},
created: function() {
this.fetchUserData()
},
methods: {
fetchUserData: function() {
this.$http.get('/Account/CurrentUserInfo').then(data => {
this.currentUser = data
this.loading = false
}, response => {
this.loading = false
this.error = true
});
}
}
}
</script>