Laravel Inertia Ziggy Link Routing Issue - vue.js

I'm currently having a problem in my routing. Here's the scenario:
Inertia is working fine when there's no id query.
But after navigating to edit and I want to click any of the navigation links like clicking the Dashboard link, it throws a 404 code saying the page does not exist. Simply because instead of removing the /category/{id}, it adds dashboard at the end instead of removing the query.
Is there a way to fix this by not violating the inertia routing?
Here's the code:
Authenticated Layout
const navigation = [
{ name: 'Dashboard', href: 'dashboard', current: false },
{ name: 'Category', href: 'category', current: false },
]
<nav class="hidden lg:flex lg:space-x-8 lg:py-2" aria-label="Global">
<Link v-for="item in navigation" :key="item.name"
:href="item.href" :class="[item.current ? 'bg-gray-100
text-gray-900' : 'text-gray-900 hover:bg-gray-50
hover:text-gray-900', 'rounded-md py-2 px-3 inline-flex
items-center text-sm font-medium']" :aria-
current="item.current ? 'page' : undefined">{{ item.name
}}</Link>
</nav>

Have you tried using Ziggy? Ziggy Github repo
Then the routes you create using Laravel are made available using the same route function in Vue. It works well with inertia when creating laravel apps.
<Link
:href="route('frontend.categories.show', [categories, post.slug])"
>
If you check your console in the page inspector it should show you the ziggy routes pulled from the "web.php" in json format.
It automatically makes the standard Controller class functions available for your routes in javascript (so index, create, edit, show, destroy functions).
I would be happy to share my code I created from a tutorial utilising breeze like you are.

Solved it. Just needed to add "/" to the href navigation object.
const navigation = [
{ name: 'Dashboard', href: '/dashboard', current: false },
{ name: 'Category', href: '/category', current: false },
]

Related

Vue Router does not redirect to the right page

When I try to push a new profile with an profileID with VueRouter I get an error saying: Avoided redundant navigation to current location: "/user/ID". When clicking on the button it is not redirecting me to another page, it just jumps to the beginning of the current page.
I declared my routes in my index.js file like this:
const routes = [
{
path: '/',
name: 'EntryPoint',
component: EntryPoint
},
{
path: '/main',
name: 'Main',
component: Main
},
{
path: '/user/:id',
name: 'User Current',
component: CurrentUser
},
When I am on an user page the path in the url already contains an userID - so f.e. #/user/1111.
Now on the same user page I want to navigate to another user when the user clicks on a button:
<ContactCard
v-for="user in users"
#goToUser="goToUser(user.id)"
/>
goToUser(userId) {
this.$router.push({ name: "User Current", params: { id: userId } });
},
The id which I get from my users array contains different id´s for each user.
Any suggestions why the routing is not working properly?
When clicking on the button I see for an instance that the url is changing with the right path: #/user/1112. Inseatd of updating the page it removes the url, jumps to top and gives me the error message from above when selecting the button again.
When I log
console.log(this.$route.path);
on button click I get the correct route - /user/ID but it is not updating anything.
UPDATE:
As Zdravko Pernikov suggested I keyed my and it works:
<template>
<div id="app">
<div id="nav">
<label>Welcome</label>
<router-link to="/main">Welcome</router-link>
<router-link to="/User">User</router-link>
</div>
<router-view :key="$route.path"/>
</div>
</template>
This may happen because you are reusing your CurrentUser component and you are not listening for changes since it's already rendered.
You can try keying your global router view <router-view :key="$route.path"></router-view> your components will be rerendered on different routes.

VUE.js Routing Configuration

I am creating an application where I have a list of users, when I click on a single user, it takes me to that specific users profile. I am using ASP.NET Core API with Vue.js as my front end. My API is working so when I click on the user, I am able to see the data coming from my database using Chrome dev Tools and Postman. However, once my page redirects to their profile, that page is blank. When I look in dev tools, I can see that its hitting my API and getting the correct information when looking at the preview tab.
So my question is, why is my page blank and not providing me with that users information. Can someone help me look at my routing, I think that is where my issue is?
I am passing their lastName as the param, but eventually I will pass a unique id
Here is my Profile.vue page, this is where I should see the users profile
<template>
<div class="container">
<v-card>
<v-data-table :headers="headers"
:items="records"
:search="search">
<template slot="items" slot-scope="records">
<td class="text-xl-left">{{ records.item.firstName }}</td>
<td class="text-xs-left">{{ records.item.email }}</td>
<td class="text-xs-left">{{ records.item.phone }}</td>
<td class="text-xs-left">{{ records.item.city }}</td>
<td class="justify-center layout px-0"></td>
</template>
</v-data-table>
</v-card>
</div>
</template>
<script>
import api from '../store/api.js'
export default {
data() {
return {
records: {},
headers: [
{ text: 'Full Name', value: 'fullName' },
{ text: 'Email', value: 'email' },
{ text: 'Phone', value: 'phone' },
{ text: 'City', value: 'city' },
{ text: 'Actions', value: 'name', sortable: false }
]
}
},
async created() {
this.GetInquiriesByUser()
},
methods: {
async GetInquiriesByUser() {
this.loading = true
try {
this.records = await api.GetInquiriesByUser()
} finally {
this.loading = false
}
},
}
}
</script>
I am using router.push to route me to the user profile from the previous page (the list)
editItem(lastName) {
this.$http.get(`http://localhost:61601/api/GetInquiry/${lastName}`)
this.$router.push({ path: `/Profile/${lastName}` })
},
Here is my routes.js file - I really think my error is in this, but cant seem to figure it out.
export const routes = [
{ name: 'home', path: '/', component: HomePage, display: 'Home', icon: 'home' },
{ name: 'AdminInquiry', path: '/Inquiry/AdminInquiry', component: AdminInquiry, display: 'Admin', icon: 'list' },
{ name: 'Profile', path: `/Profile/:lastName`, component: Profile }
]
I'm guessing that this is an issue with the router setup not matching your backend. The blank page can be indicative of this.
for your vue page, the default Router mode is hash which uses a url hack, which is that changes to anything after # character (with some caveats) do not cause the browser to redirect. So when you're going from let's say localhost:80#/Inquiry/AdminInquiry to localhost:80#/Profile/Drumpf, the change is handled entirely by the vue application. If however if you navigate from localhost:80/Inquiry/AdminInquiry to localhost:80/Profile/Drumpf the navigation is more complex. The js can handle the transition by artificially changing the url without an actual redirect taking place, if the event is triggered using js. If, however, that happens using a standard anchor, your browser redirect gets triggered, and it's up to your server-side application to handle what route is passed to the js app.
It looks like you're looking to implement history mode. This requires defining the mode as history in the vue app, and making the appropriate changes for your ASP, nginx, or apache to handle the routes. More info here: https://router.vuejs.org/guide/essentials/history-mode.html

Router link not calling router view on nested routes

I have a router
routes: [
{
path: '/',
name: 'home',
meta : {
label : 'Home'
},
component: Home
},
{
path: '/usuarios',
name: 'usuarios',
meta : {
label : 'Usuarios'
},
component: Users,
children : [
{
path: '/listar',
meta : {
label : 'Listar'
},
name : 'listUser',
component: Wrapper,
},
{
path: '/cadastrar',
meta : {
label : 'Cadastrar !'
},
name : 'userCreate',
component: UserCreate
},
],
},
]
And I have a template for rendering this router at my navbar
<div class="main">
<ul class="menu-list">
<li v-for="item in menus" v-on:click="toggleActive(item)">
<router-link class="font-gray" :to="item.path" :exact="true">{{item.meta.label}}</router-link>
<ul class="menu-list" v-if="item.children && item.isActive">
<li v-for="child in item.children">
<router-link class="font-gray" :to="{path : item.path+child.path}" :exact="true" :append="true" >{{child.meta.label}}</router-link>
</li>
</ul>
</li>
</ul>
</div>
When I click on the first router-link, the view is rendered with no problem at the router view. But when I click on the router link of childrens, it does not work,
Anyone have any idea why?
I finally figured it out.
If you have children, the father component should have a <router-view> as well
Found the answer here: Vue router2 not catching deep nested routes
Thanks everybody for trying help
This issue is happening because you have forward slashes / prepended to the paths of your nested routes.
From the documentation on nested routes:
Note that nested paths that start with / will be treated as a root path. This allows you to leverage the component nesting without having to use a nested URL.
This means that, even though your "listar" route is a child of your "usuarios" route, the path is /listar, not /usuarios/listar.
You should remove the forward slashes from the paths of your nested routes, and then specify the path in your template like so:
:to="{ path : item.path + '/' + child.path }"

Issue with Highcharts not rendering in Durandal/Hot Towel Template

We're using HighCharts.js in a Durandal/Hot Towel template in ASP.NET MVC 4. We are simply showing a proof of concept in using a charting API for a dashboard page. However, the graph is not rendering on the page during page load.
We have a custom .js file that holds the following code (copied and pasted from HighCharts.com):
$(document).ready(function () {
$('#reportgraph').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
});
And a div in an HTML view that is rendering correctly:
<div class="row-fluid">
<div class="span12">
<div class="widget">
<div class="widget-header">
<div class="title">Highcharts</div>
</div>
<div class="widget-body">
<div id="reportgraph" style="width:100%"></div>
</div>
</div>
</div>
</div>
The script bundler contains the following files:
.Include("~/Scripts/jquery-1.9.1.min.js")
.Include("~/Scripts/highcharts.js")
.Include("~/Scripts/custom.js")
.Include("~/Scripts/bootstrap.js")
.Include("~/Scripts/knockout-{version}.debug.js")
.Include("~/Scripts/sammy-{version}.js")
.Include("~/Scripts/toastr.js")
.Include("~/Scripts/Q.js")
.Include("~/Scripts/breeze.debug.js")
.Include("~/Scripts/moment.js"));
Yet the graph does not render. I've been able to successfully render the graph in a Bootstrap application, working with the scripts listed above.
Is there an extra step that must be done in order to work with functions inside document.ready statements on a single page application?
Thanks in advanced!
In a typical Durandal app there's no need to use document ready as at that point only the content of index.html (applicationHost) has been rendered. Everything else gets injected into the DOM by using Durandal's composition.
In order to work with these composed DOM fragments add a viewAttached callback in the vm that accompanies the html view. viewAttached gets the composed view passed in as parameter, which should be used to restrict the jQuery selector.
function viewAttached(view) {
$('#reportgraph', view).highcharts({
...
});
};
In most instances that should be sufficient to get jQuery plugins working. However in Durandal 1.2 viewAttached just ensures that the composed fragment is attached to its parent element not necessarily to the DOM, so you'd have to check if this is sufficient to get highcharts working. That issue will be addressed in upcoming Durandal 2.0 by introducing a documentAttached callback.

Durandal.js: change navigation options per area

I want to have different navigation per "area" of my durandal application. I've achieved this with ASP.NET MVC when using Areas by defining a Nav section in the layout page and having nested layout pages which implement the nav for each area. The view structure in durandal is as follows:
http://i1346.photobucket.com/albums/p697/user2269352/viewstructure_zps5e21e724.gif
I'm using the ASP.NET MVC4 durandal template and I am guessing that I might need to change the following segement from shell.html
<ul class="nav" data-bind="foreach: router.visibleRoutes">
<li data-bind="css: { active: isActive }">
<a data-bind="attr: { href: hash }, html: name"></a>
</li>
</ul>
I suppose that ideally I'd like to have separate html pages that could be loaded into this section depending on which area / page I am viewing.
You can accomplish this by adding a settings object to your route info, and specifying the area name there. With that in place, create a computed observable against the router's visibleRoutes collection that selects only the routes for the current area.
Not sure what your route configuration looks like, but an example of adding settings would be something like this:
var routes = [
{ url: 'one/page1', moduleId: 'viewmodels/one/page1', name: 'Page 1', visible: true, settings: {area: 'one'} },
{ url: 'two/page1', moduleId: 'viewmodels/two/page1', name: 'Page 1', visible: true, settings: {area: 'two'} }
];
router.map(routes);
In your view model where you are controlling the navigation html:
//filter the visible routes for the current area
viewModel.areaRoutes = ko.computed(function () {
var area = this.area;
return ko.utils.arrayFilter(router.visibleRoutes(), function (route) {
return route.settings.area === area;
});
}, viewModel);
Joseph Gabriel based solution works for me and playing with router.activeItem.settings.areSameItem I can set every route's group anywhere at my layout.
router.activeItem.settings.areSameItem = function (currentItem, newItem, activationData) {
return currentItem == newItem; //replace this with your own code
};