Laravel Vuejs2 missing param for named route - vuejs2

I am having a hard time trying to isolate the console error.
My code is as follows:
myside.blade.php has:
<div class="nav-container">
<ul class="nav nav-icons justify-content-center" role="tablist">
<li class="nav-item">
<div>
<router-link class="nav-link text-primary" :to="{ name: 'property', params: { customerId: {{ $property_data[0]->listingId }} }}" #click.native="isVisible = !isVisible">
<i class="nc-icon nc-key-25"></i>
<br> Property
</router-link>
</div>
</li>
<li class="nav-item">
<router-link class="nav-link text-primary" :to="{ name: 'booking' }" #click.native="isVisible = !isVisible">
<i class="nc-icon nc-chart-pie-36"></i>
<br> Bookings
</router-link>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-preferences-circle-rotate"></i>
<br> Performance
</a>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-money-coins"></i>
<br> Revenue
</a>
</li>
<li class="nav-item">
<a class="nav-link text-primary" href="" role="tab">
<i class="nc-icon nc-layers-3"></i>
<br> Integration
</a>
</li>
</ul>
</div>
<property-page :customer-Id="{{ $property_data[0]->listingId }}" v-if="isVisible"></property-page>
<router-view></router-view>
My routes.js file:
import VueRouter from 'vue-router';
let routes = [
{
path: '/property/:customerId',
name: 'property',
component: require('./components/PropertyPage'),
props: true
},
{
path: '/booking',
name: 'booking',
component: require('./components/BookingPage')
}
];
export default new VueRouter({
routes,
linkActiveClass: 'nav-link text-success'
});
my app.js file:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import router from './routes';
import PropertyPage from './components/PropertyPage.vue';
import BookingPage from './components/BookingPage.vue';
new Vue({
el: '#root',
router,
data: {
NavPrimaryClass: 'nav-link text-primary',
NavClass: 'nav-link',
isVisible: true
},
components: {
'property-page': PropertyPage,
'booking-page': BookingPage
}
})
my PropertyPage.vue file:
<template>
<div>
<div class="ajax-loader">
<img src="/loader/ajax-loader.gif" width="300px" v-if="loading" />
</div>
<div v-if="propertyDataCheck">
</div>
</div>
</template>
<script>
import moment from 'moment';
import axios from 'axios';
export default {
props: {
customerId: {
type: Integer,
required: true,
default: 0
}
},
data() {
return {
propertyData: [],
loading: false
}
},
computed: {
propertyDataCheck () {
return this.propertyData.length;
}
},
mounted() {
this.loading = true;
axios.get('/ajax/propertydata/' + this.customerId)
.then(function(response) {
this.propertyData = response.data;
this.loading = false;
}.bind(this))
.catch(function() {
this.loading = false;
}.bind(this));
}
}
</script>
<style>
.ajax-loader {
position: absolute;
left: 40%;
top: 15%;
margin-left: -32px; /* -1 * image width / 2 */
margin-top: -32px; /* -1 * image height / 2 */
}
</style>
The end result, a console error which I have spent hours trying to work out where it is coming from.
Error:
[vue-router] missing param for named route "property": Expected "customer" to be defined
I needed a component to be loaded upon page load (outside of vue-router) which is why I have <property-page :customer-Id="{{ $property_data[0]->listingId }}" v-if="isVisible"></property-page> tags and is bound to a method which will switch upon a router-link click (in case you were wondering).
My understanding of this error is the variable for the first router-link which is generated from a Laravel model DB query {{ $property_data[0]->listingId }} should be checked within a v-if wrapped around the vue-router? I have also done this to no avail.
Any help would be much appreciated!

Believe it or not, you need to use strict kebab-case (all lower case!) html-properties in vue-templates. Change customer-Id to customer-id
<property-page :customer-Id=... // does not get mapped to this.customerId
<property-page :customer-id=... // does get mapped to this.customerId, yay!

Related

Nested routes don't follow the defined pattern. VUEjs

I'm facing a new issue with nested routes. I've 2 levels of nested routes, and they're not working correctly.
Here are the routes object:
import Login from './components/auth/Login.vue';
import Dashboard from './components/dashboard/Dashboard.vue';
import Signup from './components/auth/Signup.vue';
import Home from './components/shared/Home.vue';
import ProductsHome from './components/dashboard/Products/ProductsHome.vue';
import ProductOverview from './components/dashboard/Products/ProductsOverview.vue';
import CreateProduct from './components/dashboard/Products/CreateProduct.vue';
import CreateCategory from './components/dashboard/Category/CreateCategory.vue';
import EditCategory from './components/dashboard/Category/EditCategory.vue';
import {store} from './store/store.js';
export const routes = [
{path: '/', component: Home},
{ path: '/login', component: Login },
{ path: '/registrarse', component: Signup },
{
path: '/dashboard',
component: Dashboard,
name: 'dashboard',
beforeEnter: (to, from, next) => {
if(to.name === 'dashboard') {
if(store.state.User.credentials.tokenId === null) {
next('/');
//TODO, Hacerlo global y verificar que el dashboard y sus hijos no accedan.
} else {
next();
}
}
next();
},
children: [
{
path: 'productosHome',
component: ProductsHome,
children: [
{
path: '',
component: ProductOverview
},
{
path: 'crearProducto',
component: CreateProduct
},
{
path: 'crearCategoria',
component: CreateCategory
},
{
path: 'editarCategorias',
component: EditCategory
}
]
}
]
}
];
The thing is with the dashboard. When I enter the dashboard or any of its sub-routes (with its router-link component) they don't follow the proper URL path. For example: If a visit the 'productosHome' the URL it's just '/productosHome' and not '/dashboard/productosHome. This same problem applies for every productosHome's child route.
Now, let me show to you my templates:
Dashboard.vue
<template>
<div>
<div class="container is-fluid has-background-light">
<h1 class="title has-text-centered pt-3">Dashboard</h1>
</div>
<section class="section py-3 has-background-light prueba section-dashboard">
<div class="container is-fluid remove-padding dashboard">
<aside class="nav-aside has-background-white">
<div>
<!--El anchor sera nuestro router-link-->
<!-- aside-link-active -->
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-users"></i>
</span>
<span class="aside-link-text">Clientes</span>
</a>
</div>
<div>
<router-link class="aside-link"
active-class="aside-link-active"
to="productosHome">
<span class="icon">
<i class="fas fa-tags"></i>
</span>
<span class="aside-link-text">Productos</span>
</router-link>
</div>
<div>
<a href="#" class="aside-link">
<span class="icon">
<i class="fas fa-boxes"></i>
</span>
<span class="aside-link-text">
Pedidos
</span>
</a>
</div>
</aside>
<div class="main-content has-background-white">
<router-view></router-view>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.aside-link.aside-link-active:hover {
color: white;
}
</style>
ProductsHome.vue
<template>
<div>
<div class="tabs is-medium pt-2 mb-0">
<ul>
<!-- is-active -->
<router-link to="crearProducto"
active-class="is-active"
tag="li">
<a>Crear</a>
</router-link>
<li><a>Editar</a></li>
<li><a>Buscar</a></li>
<router-link to="crearCategoria"
active-class="is-active"
tag="li">
<a>| Crear categoría</a>
</router-link>
<router-link to="editarCategorias"
active-class="is-active"
tag="li">
<a>Editar categoria</a>
</router-link>
</ul>
</div>
<div class="main-content__content block p-2">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
Note that Products Home also have children.
Also, I'm debugging routes with the famous Vue plugin and see what says:
'/' is marked has active, Is that correct?
I'm confused :D
The routes file is correct. The issue is with the router link on both files. there are 2 ways you can define router-link>to.
Absolute / Relative Path.
Absolute Path(From any file)
<router-link to="/dashboard/productosHome/">Products Home</router-link>
Relative Path(From dashboard page)
<router-link to="productosHome">Products Home</router-link>
Route object. (From any file)
<router-link :to="{ path: `/dashboard/productosHome/`}">Products Home</router-link>
No 2 gives you a bit more control. you can now name the route and use them. Like you did for dashboard main route. name: 'dashboard',. Now you can name the subroute.
{
path: 'crearProducto',
component: CreateProduct,
name: 'crearProducto'
},
router link will be
<router-link :to="{ name: 'crearProducto'}">Crear Producto</router-link>
Check Documentation for more https://router.vuejs.org/api/#to
When declaring paths in the to attribute of router-link, you need to define the full path including the root "/". E.g.: "/dashboard/productosHome"

Error : vue Maximum call stack size exceeded

i'm building an app, i tried to do router for login page but it give me this error :
vue.runtime.esm.js?2b0e:4484 Uncaught RangeError: Maximum call stack size exceeded, is there anything i did wrong
thank you for your help hopefully u can give me a hint on how to fix it
this is the Login Components
<template>
<div class="hello">
Login
</div>
</template>
<script>
export default {
name: '',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
Home Components
<template>
<div class="hello">
<header class="globalNav noDropdownTransition">
<div class="container-lg">
<ul class="navRoot">
<li class="navSection logo">
<a class="rootLink item-home colorize" href="/"><h1>Charity Finder</h1></a>
</li>
<li class="navSection primary">
<a class="rootLink item-products hasDropdown colorize" data-dropdown="products">
Products
</a>
<a class="rootLink item-developers hasDropdown colorize" data-dropdown="developers">
Developers
</a>
<a class="rootLink item-company hasDropdown colorize" data-dropdown="company">
Company
</a>
</li>
<li class="navSection secondary">
<a class="rootLink item-support colorize" href="">
Support
</a>
<router-link class="rootLink item-dashboard colorize" to="/login"> Sign in</router-link>
</li>
</ul>
</div>
</header>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
This the router Router
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
}
]
const router = new VueRouter({
routes
})
export default router

Vue computed function to match elements from 2 different arrays

Currently, I'm working with Vue v2.x.x. I have an array:
sectionTitles = ['Technology', 'Data', 'Poverty and Research', ...]
and I have jobsData that looks like this:
[{'title': 'Software Engineer', mainTag: 'Data', ...}...]
I want to display <li> in an <ul> when the sectionTitle matches the job.mainTag.
I was reading in the Vue docs that you shouldn't combine v-if with v-for, so I created a computed method to be able to filter the jobs. Here is what I did so far:
window.onload = function () {
var app = new Vue({
delimiters: ['${', '}'],
el: '#app',
data: {
jobs: jobsData,
sectionTitles: ['Data','Poverty Research Unit', 'Technology']
},
computed: {
matchingTitles: function (sectionTitle) {
return this.jobs.filter(function (job, sectionTitle) {
job.mainTag === sectionTitle;
})
}
}
})
}
<div id="app">
<template v-for="title in sectionTitles">
<h4 class="h3">{{ title }}</h4>
<ul class="list-none p-0 color-mid-background" id="jobs-list">
<li class="py-1 px-2" v-for="job in matchingTitles(title)">
<a :href="`${job.url}`">
${job.title}
</a>
</li>
</ul>
</template>
</div>
So basically I want to only display <li> when the sectionTitle (for example Data) matches the job.mainTag. How can I go about achieving this in Vue?
Change your computed method to just a method. Then change your filter to return a value. Also for displaying in Vue you want to use {{....}} not ${...}
new Vue({
el: '#app',
data: {
jobs: [{'title': 'Software Engineer', mainTag: 'Data'}],
sectionTitles: ['Data','Poverty Research Unit', 'Technology']
},
methods: {
matchingTitles: function (sectionTitle) {
return this.jobs.filter ((job)=>{
return job.mainTag === sectionTitle;
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="title in sectionTitles">
<h4 class="h3">{{ title }}</h4>
<ul class="list-none p-0 color-mid-background" id="jobs-list">
<li class="py-1 px-2" v-for="job in matchingTitles(title)">
<a :href="job.url">
{{job.title}}
</a>
</li>
</ul>
</template>
</div>
#depperm's answer works well (+1), but I'll offer a more render-efficient alternative. Computed properties are cached, so you could avoid the work of matchingTitles() on re-render. In addition, it might be easier to comprehend the template alone without having to jump to the implementation of matchingTitles().
I recommend computing the entire list to be iterated, mapping sectionTitles to the appropriate iterator object:
computed: {
items() {
return this.sectionTitles.map(title => ({
title,
jobs: this.jobs.filter(job => job.mainTag === title)
}))
}
}
Then, you'd update the references in your template to use this new computed prop:
<template v-for="item in 👉items👈">
<h4>{{ item.title }}</h4>
<ul>
<li v-for="job in 👉item.jobs👈">
<a :href="job.url">
{{ job.title }}
</a>
</li>
</ul>
</template>
new Vue({
el: '#app',
data: {
jobs: [{'title': 'Software Engineer', mainTag: 'Data'}],
sectionTitles: ['Data','Poverty Research Unit', 'Technology']
},
computed: {
items() {
return this.sectionTitles.map(title => ({
title,
jobs: this.jobs.filter(job => job.mainTag === title)
}))
}
}
})
<script src="https://unpkg.com/vue#2.6.11/dist/vue.min.js"></script>
<div id="app">
<template v-for="item in items">
<h4 class="h3">{{ item.title }}</h4>
<ul class="list-none p-0 color-mid-background" id="jobs-list">
<li class="py-1 px-2" v-for="job in item.jobs">
<a :href="job.url">
{{ job.title }}
</a>
</li>
</ul>
</template>
</div>

Vue.js Router change url but not view

I see this bug in console:
[Vue warn]: Property or method "product" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
My template id="productDetail" not receive the property "product" of the template id="product" I don't know how I can push this, please see my cod.
HTML LIST
That's ok when I click the router-link the url change to:
/product/iphone-x-64-gb for example.
<template id="product" functional>
<div class="wrapper">
<ul class="row">
<li v-for="(product, index) in products" class="col l4 m6 s12">
<div class="card-box">
<div class="card-image">
<img :src="product.images" :alt="product.images" class="responsive-img"/>
</div>
<div class="card-content">
<h3>{{ product.brand }}</h3>
<span class="price-used"><i class="used">{{ index }} gebrauchte Roomba 651</i></span>
</div>
<div class="card-action row">
<span class="col s6 price"><span>{{ product.price }}</span>
</div>
<div>
<router-link class="btn btn-default light-green darken-3" :to="{name: 'product', params: {product_id: product.id}}">meer detail</router-link>
</div>
</div>
</li>
</ul>
</div>
HTML PRODUCT DETAIL (THAT NO RECEIVE THE "product")
<template id="productDetail" functional>
<div class="row">
<div class="col s12 m6">
<img src="images/iphone-8-64-gb.jpg" alt="product.images" class="responsive-img"/>
</div>
<div class="col s12 m6">
<h3>{{ product.title }}</h3>
<h5>{{ product.price }}<h5>
<div class="col s12 m6">
<a class="waves-effect waves-light btn light-green darken-3"><i class="material-icons left">add_shopping_cart</i>kopen</a>
</div>
<div class="col s12 m6">
<router-link class="btn btn-default light-green darken-3" :to="{path: '/'}">
<span class="glyphicon glyphicon-plus"></span><i class="material-icons left">arrow_back</i>terug
</router-link>
</div>
</div>
</div>
THE .JS
var List = Vue.extend(
{
template: '#product',
data: function ()
{
return {products: [],};
},
created: function()
{
this.$http.get('https://api.myjson.com/bins/17528x').then(function(response) {
this.products = response.body.products;
}.bind(this));
},
});
const Product =
{
props: ['product_id'],
template: '#productDetail'
}
var router = new VueRouter(
{
routes: [
{path: '/', component: List},
{path: '/product/:product_id', component: Product, name: 'product'},
]
});
var app = new Vue(
{
el: '#app',
router: router,
template: '<router-view></router-view>'
});
Thank for your help.
Your props should be props: ['product'] instead of props: ['product_id']
<parent-component :product="product"></parent-component>
ChildComponent.vue
export default {
name: 'child-component',
props: ['product']
}
First activate props on the route:
var router = new VueRouter({
...
path: '/product/:product_id',
component: Product,
name: 'product',
props: true // <======= add this line
},
...
Now the product_id will be set on the Product component.
So, you want to display the whole product information, but at this moment you only have the product_id. The solution is to fetch the product:
const Product = {
props: ['product_id'],
template: '#productDetail',
data: function() { // <============ Added from this line...
return {
product: {} // add {} so no error is thrown while the product is being fetched
};
},
created: function() {
var productId = this.product_id;
// if there is a URL that fetches a given product by ID, it would be better than this
this.$http.get('https://api.myjson.com/bins/17528x').then(function(response) {
this.product = response.body.products.find(function (product) { return product.id == productId });
}.bind(this));
} // <============ ...to this line.
}
Check JSFiddle demo here of the solution above.
Alternative solution: passing the whole product as prop
Pass the product in the params: (along with product_id):
<router-link class="btn btn-default light-green darken-3" :to="{name: 'product',
params: {product_id: product.id, product: product}}">meer detail</router-link>
^^^^^^^^^^^^^^^^^^
Activate props on the route:
var router = new VueRouter({
...
path: '/product/:product_id',
component: Product,
name: 'product',
props: true // <======= add this line
},
...
Finally, add product so you can use it:
const Product = {
props: ['product_id', 'product'], // <======= added 'product' here
template: '#productDetail'
}
Demo JSFiddle for this solution here.

UserStore (Vuex) in vue and Laravel 5.4

I have promble to implement vuex
this my code :
laravel/resources/assets/js/app.js
import router from './routes.js';
import store from './store.js'
require('./bootstrap');
router.beforeEach((to,from,next) => {
if(to.matched.some(record => record.meta.requiresAuth)){
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
if(authUser && authUser.access_token){
next()
}else{
next({
path: '/login',
query: { redirect: to.fullPath }
})
}
}
next()
})
Vue.component('top-menu',require('./components/topMenu.vue'))
const app = new Vue({
el: '#app',
router,store
});
laravel/resources/assets/js/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import userStore from './components/user/userStore.js'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !=='production'
export default new Vuex.Store({
module:{
userStore
},
strict: debug
})
laravel/resources/assets/js/components/user/userStore.js
const state = {
authUser: null
}
const mutations = {
SET_AUTH_USER (state, userObj){
state.authUser = userObj
}
}
const actions ={
setUserObject: ({commit}, userObj) => {
commit('SET_AUTH_USER',userObj)
}
}
export default {
state, mutations, actions
}
this topMenu laravel/resources/assets/js/components/topMenu.vue
<script>
import {mapState} from 'vuex'
export default {
computed: {
mapState(){
userStore: state => state.userStore
}
},
created() {
const userObj = JSON.parse(window.localStorage.getItem('authUser'))
this.$store.dispatch('setUserObject',userObj)
}
}
</script>
<template>
<div>
<pre>{{ userStore }}</pre>
<nav class="navbar navbar-default navbar-static-top" >
<div class="container">
<div class="navbar-header">
<!-- Collapsed Hamburger -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Branding Image -->
<a class="navbar-brand" href="/">
Laravel
</a>
</div>
<div class="collapse navbar-collapse" id="app-navbar-collapse">
<!-- Left Side Of Navbar -->
<ul class="nav navbar-nav">
</ul>
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right" v-if="userStore.authUser !== null && userStore.authUser.access_token">
<!-- Authentication Links -->
<router-link to="/login" tag="li"><a>Login</a></router-link>
<router-link to="/register" tag="li"><a>Register</a></router-link>
<router-link to="/vendor/profile" tag="li"><a>Profile</a></router-link>
</ul>
</div>
</div>
</nav>
</div>
</template>
if I run the code I have erro
[vuex] unknown action type: setUserObject
[Vue warn]: Property or method "userStore" is not defined on the
instance but referenced during render. Make sure to declare reactive
data properties in the data option. (found in at
/var/www/html/wingding/resources/assets/js/components/topMenu.vue)
[Vue warn]: Error in render function: (found in at
/var/www/html/wingding/resources/assets/js/components/topMenu.vue)
TypeError: Cannot read property 'authUser' of undefined
[Vue warn]: Error in mounted hook: (found in at
/var/www/html/wingding/resources/assets/js/components/Home.vue)
Please help me and thanks!!
The error:
TypeError: Cannot read property 'authUser' of undefined
Should get fixed by adding following null check.
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right" v-if="userStore && userStore.authUser && userStore.authUser.access_token">