<ul>
<router-link to="/" tag="li" active-class="active" exact><a >Home</a></router-link>
<router-link to="/contact" tag="li" exact><a>contact</a></router-link>
<router-link to="/other" tag="li" exact><a>other</a></router-link>
<ul/>
Test.spec.js
(i am trying to trigger the click event and check the other component is loaded or not)
await wrapper.findAll('a').at(2).trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.contains('This is other Page')).toBe(true)
but the test is failing
You dont need to do test about router-link, the behavior of this you dont care, becouse; the behavior that you need is only know that the is rendered. No more.
You can do test like this
const wrapper: any = shallowMount(YourComponent, {
stubs: ['router-link', 'router-view']
});
expect(wrapper.html()).toContain('to="/contact"');
Other thing that you can doing is verify that the prop "to" recived exactly the string "/contact"
For me, is enough .toContain(...)
PD: sorry for my english.
Related
Im new to Vue and i want while on mobile navigation when I click menuItem I run function toggleMenu(open/close Menu), but then whole page reload, who to prevent that?
This is my link:
<router-link to="/" #click="toggleMenu">
<div class="nav-item">Home</div>
</router-link>
I tried adding #click.prevent and it prevents reload but not sending me to path.
EDIT:
So i make it works thanks to Boussadjra Brahim answer, but I did it with CompositionAPI and i used useRouter() hook from vue-router
Template:
<router-link
to="/"
#click.prevent="toggleMenu">
Home </router-link>
setup():
const router = useRouter();
function toggleMenu(){
router.push('/');
}
Add prevent modifier as you did then inside the toggleMenu add this.$router.push("/"); :
<router-link to="/" #click.prevent="toggleMenu">
<div class="nav-item">Home</div>
</router-link>
LIVE DEMO
I'm using React Router 4. One concern I have is that if you use the <Link /> component to navigate between routes, lets say in your header, and you click on that same link again it will keep pushing the same url to browser history? Is there any way to prevent this behaviour, or is it completely up to me as developer to either replace that <Link /> with something something like a <span> element (if I dont want users to be able to click that link)?
Or should I do my own version of the <Link /> component and then inside that prevent from firing events when on the same route?
Yes, agree with #MaximeGirou. You can use your own trick.
Or another way is to define a class with some CSS properties [like cursor:not-allowed etc.] and give that class name in activeClassName attribute.
<NavLink to="/dashboard" activeClassName="linkActive">
<i className="icon icon-home" /> <span>Dashboard</span>
</NavLink>
I'm trying to have a list component, which renders a list of router-links with a scoped slot for each of the router-link. The to-prop of the router-link should be configurable by the parent.
The parent component should be able to configure the to-prop of the router link, without having to implement the router-link itself. Or if it has to implement the router-link itself, the list component should be able to pass classes to every router-link.
I've created a codepen showing the problem that I want to solve. Of course if you have any questions about it or if anything's unclear let me know.
https://codepen.io/Buffalom/pen/KKPmJPx
This is a summary of what I'm trying to achieve:
<router-link v-for="item in items" to="/" class="abc">
<!-- :to should be configurable by the parent -->
<slot :item="item"></slot>
</router-link>
I expect the parent to be able to render a list with a given array of items but configure each router-links to-prop itself.
Update
The ideal way I'd like to take would be something like this in the parent component:
<List :items="items" :to="`/1/${item.name}`">
...
As the item in the to-prop each item in items would be used on the v-for router-link in the list component itself. Kind of like a reverse scoped-slot...^^
Is this what you're looking for? You just need to make to a dynamic prop.
<router-link v-for="item in items" :to="item.url" class="abc">
<!-- :to should be configurable by the parent -->
<slot :item="item"></slot>
</router-link>
Update
If you don't have the url, look into vue-router named routes. Taken from the doc and adapted lightly:
const router = new VueRouter({
routes: [
{
path: '/1/:itemName',
name: 'item',
component: MyItemPage
}
]
})
<router-link
v-for="item in items"
:to="{ name: 'item', params: { itemName: item.name }}"
class="abc"
>
<slot :item="item"></slot>
</router-link>
I have following HTML property:
<ul>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/home']">Home</a>
</li>
</ul>
I want now to get the href as a value in the unit test. So far I have in my test-case:
it('should navigate have login navigation', () => {
const debugElements = fixture.debugElement.queryAll(By.css('a.nav-link'));
debugElements.forEach(x => console.log(x.properties['href']));
});
});
But that is every time undefined. How do I fetch the href from the rounterLink directive? Incidentally, I don't need to do fixture.detectChanges(); Since I don't use lifecycle-hooks in this particular comp.
You actually have to run fixture.detectChanges(). This is not limited to lifecycle hooks but concerns change detection in general (so pretty much any magic that Angular does).
I've created a Stackblitz demonstrating that the test is failing without detectChanges and running with it.
I have found https://sean-hunter.io/2016/10/23/inter-component-communication-with-aurelia/ where it is explained how simple communication of values can be made between a parent and a child template.
Now, I'm trying to apply that to the contact manager tutorial:
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/contact-manager-tutorial/1
... also on https://github.com/aurelia/app-contacts/tree/master/src - in particular to the looped contact items, but I cannot get it to work.
I have made gists as an example, which can run on gist.run (note, gist.run seems to only work in Chrome, not in Firefox 50 yet - but you can replace gist.run/?id= with gist.github.com/ and look at the code):
Copy of original contacts manager app (works) - https://gist.run/?id=c73b047c8184c052b4c61c69febb33d8
My changes in the app (do not work) - https://gist.run/?id=47c4f1c053adbdf46f6a33413dd12d3d
This is what I'm trying to do: in the original contacts app, there is this in src/contact-list.html which works fine:
<template>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<a route-href="route: contacts; params.bind: {id:contact.id}" click.delegate="$parent.select(contact)">
<h4 class="list-group-item-heading">${contact.firstName} ${contact.lastName}</h4>
<p class="list-group-item-text">${contact.email}</p>
</a>
</li>
</ul>
</div>
</template>
Now, I'd like to replace the inner elements of the "looped" li - that is, the a with the h4 and the p - with a new template.
So, I made src/contact-list-item.html:
<template>
<a route-href="route: contacts; params.bind: {id:theContact.id}" click.delegate="$parent.$parent.select(theContact)">
<h4 class="list-group-item-heading">${theContact.firstName} ${theContact.lastName}</h4>
<p class="list-group-item-text">${theContact.email}</p>
</a>
</template>
... and src/contact-list-item.js:
import {bindable} from 'aurelia-framework';
export class ContactListItem {
#bindable theContact;
}
... and changed src/contact-list.html as:
<template>
<require from="./contact-list-item"></require>
<div class="contact-list">
<ul class="list-group">
<li repeat.for="contact of contacts" class="list-group-item ${contact.id === $parent.selectedId ? 'active' : ''}">
<contact-list-item theContact.bind="contact"></contact-list-item>
</li>
</ul>
</div>
</template>
Basically, I've made a property in the contact-list-item class called theContact, and I'd like to bind it to the contact which is the looper variable in the repeat.for="contact of contacts" -- unfortunately, this doesn't work, as the data is not propagated (and so the contact names are empty). Also, the clicks on contact fiels do not propagate to show the details, even if I've changed click.delegate="$parent.select(contact)" to click.delegate="$parent.$parent.select(theContact)" in the new template.
What do I have to do, in order to have the data propagate form the li repeate.for loop, down to the new replacement template - and to have the app react on clicks on the new template?
Quick answer:
In contact-list.html, change:
<contact-list-item theContact.bind="contact"></contact-list-item>
to:
<contact-list-item the-contact.bind="contact"></contact-list-item>
Explanation:
HTML is not case-sensitive, but the convention is to use only lower-case letters. To respect that, Aurelia converts all camelCase variables to dash-case parameters and element names when interfacing with your HTML code.
More Information:
Dwayne Charrington wrote a good blog about this topic here:
http://ilikekillnerds.com/2016/06/dont-get-skewered-kebab-case-aurelia/