Accessing instance data in Vue from Controller or Components - javascript

I'm using the Vue controller to update the content on my SPA. While I can import views and controllers and display them accordingly, I'm having a hard time updating some variables defined in the main Vue instance. I also tried to define them in the main view but I still cannot update them.
Here's my Vue instance:
new Vue({
router,
render: h => h(App),
data: () => {
return {
showYesOrNo: false,
showMultiChoice: false
}
}
}).$mount('#app')
This is my main view:
<script type="text/javascript">
import ContactContainer from "./views/ContactContainer.vue"
export default {
name: "app",
components:{
ContactContainer
},
data: () => {
return { // Redefined the variables here to see if I could access them in some way
showYesOrNo: false,
showMultiChoice: false
}
}
}
</script>
<template>
<div id="app">
<div class="container">
<div id="main_container">
<transition name="fade"><router-view name="YesOrNo" v-show="!showMultiChoice"/></transition>
<transition name="fade"><router-view name="MultiChoice" v-show="!showYesOrNo"/></transition>
<transition name="fade"><ContactContainer name="Contact" v-show="!showMultiChoice && !showYesOrNo"></ContactContainer></transition>
</div>
</section>
</div>
</div>
</template>
Now this is how I try to access the ShowYesOrNo and ShowMultiChoice variables. First in the controller:
const routes = [
{
path: '/YesOrNo',
components: {
YesOrNo: YesOrNoVue,
MultiChoice: MultiChoiceContainer
},
beforeEnter: (to, from, next) => {
console.log(this); //undefined
console.log(this.$parent.showYesOrNo) //undefined
console.log(vm.showYesOrNo) //undefined
next();
}
}
]
Then in the YesOrNo vue:
<template>
<!-- Some HTML -->
</template>
<script>
export default {
data: function(){
return {
name: 'YesOrNoVue'
}
},
created: function(){
console.log(this.showYesOrNo); //undefined
console.log(vm.showYesOrNo); //undefined
}
}
</script>
I'm a little confused with the visibility of these variables so I'd like to know what's the best approach to change them when the router-view is updated (i.e. when the vue is created).
Thanks.

Related

Passing vue.js Route Params to Component

I'm having trouble getting a route param to pass directly into a component. I followed multiple sets of directions in the docs (including using the Composition API as in the following code), but I'm still getting undefined when the CourseModule.vue first renders.
Route Definition
{
path: '/module/:id',
name: 'Course Module',
props: true,
component: () => import('../views/CourseModule.vue'),
},
CourseModule.vue:
<template>
<div class="AppHome">
<CustomerItem />
<CourseModuleItem :coursemodule-id="this.CoursemoduleId"/>
</div>
</template>
<script>
import { useRoute } from 'vue-router';
import CustomerItem from '../components/customers/customer-item.vue';
import CourseModuleItem from '../components/coursemodules/coursemodule-item.vue';
export default {
setup() {
const route = useRoute();
alert(`CourseModule.vue setup: ${route.params.id}`);
return {
CoursemoduleId: route.params.id,
};
},
components: {
CustomerItem,
CourseModuleItem,
},
mounted() {
alert(`CourseModule.vue mounted: ${this.CoursemoduleId}`);
},
};
</script>
coursemodule-item.vue:
<template>
<div id="module">
<div v-if="module.data">
<h2>Course: {{module.data.ModuleName}}</h2>
</div>
<div v-else-if="module.error" class="alert alert-danger">
{{module.error}}
</div>
<Loader v-else-if="module.loading" />
</div>
</template>
<script>
import Loader from '../APILoader.vue';
export default {
props: {
CoursemoduleId: String,
},
components: {
Loader,
},
computed: {
module() {
return this.$store.getters.getModuleById(this.CoursemoduleId);
},
},
mounted() {
alert(`coursemodule-item.vue: ${this.CoursemoduleId}`);
this.$store.dispatch('setModule', this.CoursemoduleId);
},
};
</script>
The output from my alerts are as follows:
CourseModule.vue setup: zzyClJDQ3QAKuQ2R52AC35k3Hc0yIgft
coursemodule-item.vue: undefined
CourseModule.vue mounted: zzyClJDQ3QAKuQ2R52AC35k3Hc0yIgft
As you can see, the path parameter works fine in the top level Vue, but not it's still not getting passed into the component.
your kebab-cased :coursemodule-id props that you're passing to the CourseModuleItem component becomes a camelCased coursemoduleId props
Prop Casing (camelCase vs kebab-case)
try this
// coursemodule-item.vue
...
props: {
coursemoduleId: String,
},
...
mounted() {
alert(`coursemodule-item.vue: ${this.coursemoduleId}`);
this.$store.dispatch('setModule', this.coursemoduleId);
},

How to convert a mention tag text to a <router-link> ? (VUEJS)

I have a body property in data
data(){
return{
body:'Hello im #username1 and #username2'
}
}
I want to convert each #user into a code below, where a user can click that link to go that url path.
<router-link :to="`/${username1}`">#{{username1}}</router-link>
What i tried
<span v-html='bodyReplaced'>
computed: {
bodyReplaced(){
return this.body.replace(
/#\w+/g,
(user) => '<router-link :to="`/${username1}`">#{{username1}}</router-link>'
)
}
}
What the code did:
Convert the string into router-link in the dom but not in the view
I dont know how to replace the # after the match, so i can use it in to="`/${username1}
I think you're looking for something like
<template v-for="part of body.split(/(#\w+)/g)">
<router-link v-if="part[0] == '#'" :to="`/${part.slice(1)}`">{{part}}</router-link>
<template v-else>{{part}}</template>
</template>
new Vue({
el: 'main',
data: {
body:'Hello im #username1 and #username2'
},
router: new VueRouter({
routes: []
}),
})
<main>
<template v-for="part of body.split(/(#\w+)/g)">
<router-link v-if="part[0] == '#'" :to="`/${part.slice(1)}`">{{part}}</router-link>
<template v-else>{{part}}</template>
</template>
</main>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
Create a component called mention and pass the user name as prop, i used the same approach of #Bergi, or you could replaced a computed property in which you replace the mention uder by a element which could be parsed not like router-link :
Vue.component('mention', {
template: `<router-link :to="'/'+user">#{{user}}</router-link>`,
props: ['user']
})
const Foo = {
template: '<div>im foo</div>'
}
const Bar = {
template: '<div>im bar</div>'
}
const routes = [{
path: '/foo',
component: Foo
},
{
path: '/bar',
component: Bar
}
]
const router = new VueRouter({
routes, // short for `routes: routes`,
})
// 4. Create and mount the root instance.
// Make sure to inject the router with the router option to make the
// whole app router-aware.
const app = new Vue({
router,
data() {
return {
body: 'Hello im #foo and #bar'
}
},
computed: {
tokens() {
return this.body.split(' ');
},
bodyReplaced() {
return this.body.split(' ').map(w => {
return w.startsWith('#') ? `${w}` : w;
}).join(' ')
}
}
}).$mount('#app')
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<div>********The first solution********</div>
<template v-for="token in tokens">
<mention v-if="token.startsWith('#')" :user="token.slice(1)"></mention>
<template v-else> {{token}} </template>
</template>
<div>********The second solution********</div>
<span v-html='bodyReplaced'></span>
<router-view></router-view>
</div>

Vue.js call component by variable name?

Is possible in Vue.js call component by variable name?
Components are registred:
import Component1 from 'component1'
import Component2 from 'component2'
import Component3 from 'component3'
...
components: {
Component1, Component2, Component3
},
And i am searching for something like this:
created() {
var componentName = 'Component1';
this.components[componentName]
}
You can access the components property like this:
this.$options.components[componentName]
Just a basic example on how you can use dynamic component:
link to jsFiddle to play around: link here
<div id="app">
<component v-bind:is="currentPage">
<!-- component changes when currentPage changes! -->
<!-- output: Updated About -->
</component>
</div>
new Vue({
el: '#app',
data: {
currentPage: 'home'
},
components: {
home: {
template: "<p>Home</p>"
},
about: {
template: "<p>About</p>"
},
contact: {
template: "<p>Contact</p>"
}
},
mounted(){
this.$options.components['about'].template = "<p>Updated About</p>"
this.currentPage = 'about'
}
})

how to export tags and computed functions to main App.vue from components in VueCLI

I'm at the very start with VUE CLI 3, and was wondering if I could make clean my code importing from the components to the main App.vue such things like tags inside the template of those components, or even computed functions of that components, here on detail my problem:
This is one of my components (header), and I want to export that input tag and its computed function to the main App.vue without precisely write all that template code and scripts in there.
<template>
<div>
<input type='text' v-model='search' placeholder='Search for Tittle or Author'/>
</div>
</template>
<script>
export default {
name:"header",
props:{
header:Object
},
computed: {
filteredTitles:function()
{
return this.bookLists.filter((data)=>{return data.title.toUpperCase().includes(this.search.toUpperCase())})
}
}
}
</script>
This is my App.Vue file already with that component imported, but the point is even the element already was imported , the input doesn't show up, unless I write its code inside the App.vue template tag in fact.
<template>
<div id="app">
<div class="card-flipping">
<books v-for="(books,index) in bookLists" v-bind:key="index" v-bind:books="books" />
</div>
</div>
</template>
<script>
import books from "./components/books.vue";
import header from './components/header.vue';
export default {
name: "app",
components: {
header,
books,
},
data() {
return {
bookLists: []
};
},
methods: {
getJsonData() {
fetch(" https://api.myjson.com/bins/zyv02 ", {
method: "GET"
})
.then(response => {
return response.json();
})
.then(bookStore => {
this.bookLists = bookStore.books;
})
.catch(error => {
console.log(error);
});
}
},
computed: {
filteredTitles:function()
{
return this.bookLists.filter((data)=>{return data.title.toUpperCase().includes(this.search.toUpperCase())})
}
},
created() {
this.getJsonData();
}
};
</script>
Could somebody help me please?

Synchronize variable between router in vue.js

I'd like to change value of a variable in a router-view by changing other variable in different routre-view synchronously. I wrote code like below to change variable isFoo in header and catch it in side bar, but it fails.
App.vue:
<template>
<v-app id="app">
<router-view name="sidebar"></router-view>
<router-view name="header"></router-view>
<router-view name="main"></router-view>
<router-view name="footer"></router-view>
</v-app>
</template>
<script>
export default {
name: 'app',
isFoo: false
}
</script>
and Sidebar.vue:
<template>
<div id="sidebar" :isOpen="isFoo"></div>
</template>
<script>
export default {
name: 'sidebar',
data () {
return {isFoo: this.$parent.$options.isFoo}
}
}
</script>
Header.vue:
<template>
<button v-on:click="foo()">Button</button>
</template>
<script>
export default {
name: 'header',
methods: {
foo: () => {
this.$parent.$options.isFoo = !this.$parent.$options.isFoo
}
}
}
</script>
Your question is essentially about how to share state across multiple components of your app, and is quite general.
Your code does not work because you have copied isFoo across your components instead of just referencing a single source of truth for that data. Also you should specify reactive data in the data property of each component, not directly within the $options of the component.
I've fixed your code to make it work:
const Header = {
template: '<button #click="$parent.isFoo = true">Click Me</button>'
}
const Sidebar = {
template: '<div>Sidebar: {{ $parent.isFoo }}</div>'
}
const router = new VueRouter({
routes: [
{
path: '/',
components: {
header: Header,
sidebar: Sidebar
}
}
]
})
new Vue({
router,
el: '#app',
data: {
isFoo: false
}
})
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>
<script src="https://rawgit.com/vuejs/vue-router/dev/dist/vue-router.js"></script>
<div id="app">
<router-view name="header"></router-view>
<router-view name="sidebar"></router-view>
</div>
However I do not recommend this approach. You really shouldn't be accessing this.$parent because it tightly couples the components.
I'm not going to go into detail about better ways of doing this because there are lots of SO questions which cover this topic.

Categories

Resources