How in livewire use route by its name? - laravel-routing

In my laravel 7 /livewire 1.3 / turbolinks:5 / alpine#v2 app I have route defined
Route::livewire('/hostel/{slug}', 'hostel.hostel-view-page')->name('hostel-view-page');
When I use it :
<a href="{{ route('hostel-view-page', $hostelsIsHomepageSpotlight->slug) }}" >
Title
</a>
it does not work as reactive, as all page is reloaded. I prefer to name of this route, not like :
<a href="/hostel/{{ $hostelsIsHomepageSpotlight->slug }}" >
Title
</a>
Which is a valid way ?
Thanks!

Try this, it works well for me:
Route::group(['prefix' => 'admin',
'as' => 'admin.',
'middleware' => 'your:middleware',
], function () {
Route::livewire('your-url-here', 'your-livewire-class-here')
->name('whatever.you.want');
});

Related

How to use i18n variables with v-for?

I have to use i18n variables for a select dropdown in the form.
I can access i18n data in main.js like this :
// Load locales
axios
.get("http://localhost:3000/data")
.then(({data}) => {
console.log(data);
appOptions.i18n.setLocaleMessage("fr", basil.get(data, "fr", {}));
appOptions.i18n.setLocaleMessage("en", basil.get(data, "en", {}));
appOptions.i18n.setLocaleMessage("nl", basil.get(data, "nl", {}));
})
.catch((error) => {
console.error(error);
});
In my form component I can use these date for example for simple field like this :
<div class="success" v-if="success">
{{ $t("contact.success_message") }}
</div>
I would like to use v-for for select options with "$t" variable . Something like this don't work :
<option
v-for="item in $t("register")"
:key="item"
:value="item"
>
{{ item }}
Can you please tell me how can I achieve this if I have to follow the structure of the json file with i18n variable :
{
es: {
contact: {
contact_demo: "Contáctenos para una demostración",
contact_sales: "Comuníquese con ventas",
...
},
register: {
option_Germany: "Alemania",
option_Morocco: "Marruecos",
option_Belgium: "Bélgica",
option_Cook Islands: "Islas Cook",
...
found the solution :
<select id="countries">
<option
v-for="value in $t('register',)"
:key="value"
>
{{ value }}
</option>
</select>

Route [murid.index] not defined. (View: D:\xampp\htdocs\MentorOnlinemu\resources\views\navigation-menu.blade.php)

I've code in file navigation-menu.blade.php
#if (auth()->user()->role_id == 2)
<x-jet-nav-link href="{{ route('murid.index') }}" :active="request()->routeIs('murid.index')">
{{ __('Murid') }}
</x-jet-nav-link>
#endif
and my code in routes/web.php
Route::group(['middleware' => 'auth'], function() {
Route::group(['middleware' => 'role:murid', 'prefix' => 'murid', 'as' => 'murid.'], function() {
Route::resource('murid', \App\Http\Controllers\MuridController::class);
});
});
But, i got error Route [murid.index] not defined.
From file navigation-menu.blade {{ route('murid.index') }} can't define. i already define in routes/web.php.
What's wrong with my code ?
Anyone can help me ?
Thanks
If you have prefix "murid" and resource is "murid", then you must call the route like
href="{{ route('murid.murid.index') }}"
That must fix the issue.

Nuxt Menu links from API...How can i detect if its a Nuxt link :to or :href?

Im building my main menu from an API :
<b-navbar-nav>
<div v-for="result in resultsmenu" :key="result.id">
<span class="hoverlink">
<nuxt-link :to="result.slug">{{result.title}}</nuxt-link>
</span>
</div>
</b-navbar-nav>
Everythings works well but one problem is in the menu from the API ..One link is external with an "href" like : https://ww.instagram.com so nuxt-link process it like a internal route i end up with :
http://localhost:3000/https://ww.instagram.com
I was wondering if there is a way to tell Nuxt that if a link is an "href" type: "link" to handle it like an external link instead of an nuxt-link to: ?
Thank you
One way to achieve this would be to use a computed property.
Assuming your resultsmenu data looks something like...
resultsmenu: [
{slug: 'http://www.website.com', title: 'link to website.com'},
{slug: '/test', title: 'link to a website.com'},
{slug: '/yay', title: 'link to b website.com'},
{slug: 'http://www.website.com', title: 'link to c website.com'}
]
You can do...
computed: {
menuLinks() {
let links = []
this.resultsmenu.forEach(link => {
let menuItem = {}
menuItem.isHttp = !!link.slug.includes('http');
menuItem.target = link.slug
menuItem.title = link.title
links.push(menuItem)
})
return links
}
}
Then in your template:
<div v-for="(result, index) in menuLinks" :key="index">
<span>
<nuxt-link v-if="!result.isHttp" :to="result.target">{{result.title}}</nuxt-link>
<a v-else :href="result.target">{{result.title}}</a>
</span>
</div>

Vue filter in v-for

Hi I am pretty new to VueJS and have started working on a very simple API request. I have an object that looks like this:
posts: [
text: "String",
choices: {"1":"Yes","2":"No"}
]
Coming from angular, this seems very straightforward. I would just use a filter to convert choices to an object and loop over it. However, I ran into a problem. When I attempt to use the filter 'log' or 'json' in the v-for, they don't work.
<template>
<div>
<li v-for="(post,index) in posts | log">
<ul>
{{ post.text | log }}
{{ post.choices | json }}
<li v-for="(value,key) in post.choices | json">
{{value}} {{key}}
</li>
</ul>
</li>
</div>
</template>
<script>
import {HTTP} from './main';
export default {
filters: {
json: function (value) {
return JSON.parse(value)
},
log: function (value) {
console.log(value)
}
},
props: [
'apiKey'
],
data: () => ({
posts: [],
post: [],
errors: []
}),
created() {
HTTP.get('questions', { headers: { 'Api-Key': this.apiKey} })
.then(response => {
this.posts = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
</script>
Then no data shows up, however they work fine in the mustache template. Any thoughts on how I can accomplish this?
tl;dr
works:
{{ post.choices | json }}
does not work:
<li v-for="(value,key) in post.choices | json">
Any work around? I can't use computed properties because this is a "sub-object" of an array and computed properties don't work that way, unless I am mistaken?
You cannot add a filter to a v-for directive.
Just parse the data before setting the posts data property:
HTTP.get('questions', { headers: { 'Api-Key': this.apiKey} })
.then(response => {
let posts = response.data;
post.forEach(p => p.choices = JSON.parse(p.choices));
this.posts = posts;
})
I don't see why you need to use JSON.parse, since the choices key refers to a valid JS object. Unless you have made a mistake, and that the choices key refers to a string.
Anyway, if you want to parse post.choice into a valid JS object, you can simply pass it into a custom function which returns the parsed JSON to v-for, for example:
<li v-for="(value,key) in postChoicesJson(post.choice)">
{{value}} {{key}}
</li>
And then declare a method for that:
postChoicesJson: function(obj) {
return JSON.parse(obj);
}
Note: Your DOM is invalid, because <li> elements must be a direct child of a <ul> or an <ol> element.

Conditional <router-link> in Vue.js dependant on prop value?

Hopefully this is a rather simple question / answer, but I can't find much info in the docs.
Is there a way to enable or disable the anchor generated by <router-link> dependent on whether a prop is passed in or not?
<router-link class="Card__link" :to="{ name: 'Property', params: { id: id }}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
If there's no id passed to this component, I'd like to disable any link being generated.
Is there a way to do this without doubling up the content into a v-if?
Thanks!
Assuming you want to disable anchor tag as in not clickable and look disabled the option is using CSS. isActive should return true by checking prop id.
<router-link class="Card__link" v-bind:class="{ disabled: isActive }" :to="{ name: 'Property', params: { id: id }}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
<style>
.disabled {
pointer-events:none;
opacity:0.6;
}
<style>
If you want to just disable the navigation , you can use a route guard.
beforeEnter: (to, from, next) => {
next(false);
}
If you need to use it often, consider this:
Create new component
<template>
<router-link
v-if="!disabled"
v-bind="$attrs"
>
<slot/>
</router-link>
<span
v-else
v-bind="$attrs"
>
<slot/>
</span>
</template>
<script>
export default {
name: 'optional-router-link',
props: {
params: Object,
disabled: {
type: Boolean,
default: false,
},
},
};
</script>
Optional, register globally:
Vue.component('optional-router-link', OptionalRouterLink);
Use it as follows:
<optional-router-link
:disabled="isDisabled"
:to="whatever"
>
My link
</optional-router-link>
The problem is that router-link renders as an html anchor tag, and anchor tags do not support the disabled attribute. However you can add tag="button" to router-link:
<router-link :to="myLink" tag="button" :disabled="isDisabled" >
Vue will then render your link as a button, which naturally supports the disabled attribute. Problem solved! The downside is that you have to provide additional styling to make it look like a link. However this is the best way to achieve this functionality and does not rely on any pointer-events hack.
I sometimes do stuff like this:
<component
:is="hasSubLinks ? 'button' : 'router-link'"
:to="hasSubLinks ? undefined : href"
:some-prop="computedValue"
#click="hasSubLinks ? handleClick() : navigate"
>
<!-- arbitrary markup -->
</component>
...
computed: {
computedValue() {
if (this.hasSubLinks) return 'something';
if (this.day === 'Friday') return 'tgif';
return 'its-fine';
},
},
But I basically always wrap router-link, so you can gain control over disabled state, or pre-examine any state or props before rendering the link, with something like this:
<template>
<router-link
v-slot="{ href, route, navigate, isActive, isExactActive }"
:to="to"
>
<a
:class="['nav-link-white', {
'nav-link-white-active': isActive,
'opacity-50': isDisabled,
}]"
:href="isDisabled ? undefined : href"
#click="handler => handleClick(handler, navigate)"
>
<slot></slot>
</a>
</router-link>
</template>
<script>
export default {
name: 'top-nav-link',
props: {
isDisabled: {
type: Boolean,
required: false,
default: () => false,
},
to: {
type: Object,
required: true,
},
},
data() {
return {};
},
computed: {},
methods: {
handleClick(handler, navigate) {
if (this.isDisabled) return undefined;
return navigate(handler);
},
},
};
</script>
In my app right now, I'm noticing that some combinations of #click="handler => handleClick(handler, navigate)" suffer significantly in performance.
For example this changes routes very slow:
#click="isDisabled ? undefined : handler => navigate(handler)"
But the pattern in my full example code above works and has no performance issue.
In general, ternary operator in #click can be very dicey, so if you get issues, don't give up right away, try many different ways to bifurcate on predicates or switch over <component :is="" based on state. navigate itself is an ornery one because it requires the implicit first parameter to work.
I haven't tried, but you should be able to use something like Function.prototype.call(), Function.prototype.apply(), or Function.prototype.bind().
For example, you might be able to do:
#click="handler => setupNavigationTarget(handler, navigate)"
...
setupNavigationTarget(handler, cb) {
if (this.isDisabled) return undefined;
return this.$root.$emit('some-event', cb.bind(this, handler));
},
...
// another component
mounted() {
this.$root.$on('some-event', (navigate) => {
if (['Saturday', 'Sunday'].includes(currentDayOfTheWeek)) {
// halt the navigation event
return undefined;
}
// otherwise continue (and notice how downstream logic
// no longer has to care about the bound handler object)
return navigate();
});
},
You could also use the following:
<router-link class="Card__link" :to="id ? { name: 'Property', params: { id: id }} : {}">
<h1 class="Card__title">{{ title }}</h1>
<p class="Card__description">{{ description }}</p>
</router-link>
If id is undefined the router won't redirect the page to the link.
I've tried different solutions but only one worked for me, maybe because I'm running if from Nuxt? Although theoretically nuxt-link should work exactly the same as router-link.
Anyway, here is the solution:
<template>
<router-link
v-slot="{ navigate }"
custom
:to="to"
>
<button
role="link"
#click="onNavigation(navigate, $event)"
>
<slot></slot>
</button>
</router-link>
</template>
<script>
export default {
name: 'componentName',
props: {
to: {
type: String,
required: true,
},
},
methods: {
onNavigation(navigate, event) {
if (this.to === '#other-action') {
// do something
} else {
navigate(event);
}
return false;
},
};
</script>