Storybook: Clicking a button redirects user - vue.js

I have a link component that I want to display in Storybook. I'm using Vue.
This is the component
NavigationLink.vue:
<ul>
<li :class="{selected: isSelected}">
<a :href="linkUrl">
<i :class="'isax isax-' + linkIcon"></i>
{{ linkName }}
</a>
</li>
</ul>
This is the story NavigationLink.stories.js:
import NavigationLink from '../app/javascript/components/NavigationLink.vue'
export default {
title: 'Navigation/Links',
component: NavigationLink,
argTypes: { ...argTypes here... }
}
const Template = (args) => ({
components: { NavigationLink },
setup() {
return { args };
},
template: '<NavigationLink v-bind="args"></NavigationLink>',
});
export const UnselectedLink = Template.bind({});
UnselectedLink.args = { ...args here... }
export const SelectedLink = Template.bind({});
SelectedLink.args = { ...args here... }
Unfortunately, you're still able to 'click' the link in Storybook and this then redirects to the 'Introduction' page within Storybook. But I don't want it to redirect there at all. In fact, if possible, I'd prefer to not be able to click it at all.
Any suggestions? Thanks in advance.

In the end I couldn't find a fancy way of doing this, so I just set the :href prop to be linkHref: '/?path=/story/navigation-links--unselected-link' in the args for UnselectedLink (and then similar for the SelectedLink). This still allows for the link to be clicked but will just redirect you back to the same story within Storybook.

Related

redirection link generate by the methods to href or nuxt-link

Hello I want to display a page with a link generated by a method.
Here is my current code.
<template>
<nuxt-link :to="seeProduct(item.sku.product.id).toString()">
<div>
<span>Go to product</span>
</div>
</nuxt-link>
</template>
<script>
export default {
methods: {
async seeProduct(id) {
const app = { $axios: this.$axios };
const urlProduct = await endPoint.getProduct(app, id);
console.log(urlProduct.url); // https://www.products/gants.html => this is the url
return urlProduct.url;
},
}
}
</script>
When I click on the link, the redirection is not good. How to do a good redirection with an URL generated by a method?
If it's an internal path, I do recommend you passing an actual path only or even better, a name as shown here: https://router.vuejs.org/guide/essentials/navigation.html#router-push-location-oncomplete-onabort
It should look something like :to="{ name: 'gants' }" when your seeProduct method is done.

how to use require.js define a template like vue component and connect the data

In projects that use express + require.js and vue cdn, I try to use require.js to define a template similar to vue components
In index.js, I have a data list, I want to use v-for in the index.html display list item, but I cannot connect the data list in html
This is my code, is there any mistake?
index.js
define([
'text!js/components/search/index.html',
'jquery',
], function (template) {
var $ = require('jquery');
var Vue = require('vue');
var ajax = require('js/ajax');
return {
name: 'search',
template: require('text!js/components/search/index.html'),
props: {
},
data: function () {
return {
// data list
Options: [],
};
},
mounted: function () {
this.loadOptions();
},
methods: {
//data list
loadOptions() {
ajax.get('/options/options').then(function (data) {
this.Options = data.Options;
console.log('this.Options Successful get data')
});
},
},
};
});
index.html
<div class="col-12 col-md-6 col-xl-6 ">
<a class="dropdown-item"
href="#"
v-for="opt in Options"
:key="opt.value">
<p :title="opt.label">
{{ opt.label }}
</p>
</a>
</div>
Maybe because of this?
I assume that console.log('this.Options Successful get data') works as expected. Try to change your loadOptions method as follows:
loadOptions() {
ajax.get('/options/options').then(data => {
this.Options = data.Options;
console.log('this.Options Successful get data')
});
},
Arrow function should help to point this to your Vue component instance.
From the code, your template file lives at components/search/index.html, is the file being referenced properly?
Better still, Please put your code in a sandbox/jsfiddle and share the link. So, it would be easy for anyone to look at it for you.

VueJS Loading template component via code?

I am trying to make a template component that I can use later on in my project. However I'm having a bit of a hard time showing it on the element I want via code.
The code I have so far is as such.
<template>
<div>
<b-alert show dismissible variant="danger" v-show="elementVisible">
<i class="mdi mdi-block-helper mr-2"></i>{{ text }}
</b-alert>
</div>
</template>
<script>
export default {
name: "alertDanager",
props: {
text: null
},
data() {
return {
elementVisible: true
};
},
created() {
setTimeout(() => (this.elementVisible = false), 5000);
}
};
</script>
I am trying to call this on an action by this
I import it
import dangerAlert from "#/components/Alerts/danger";
Then on the function I want to call it on I do this
const error = new dangerAlert({ propsData: { text: "Error message" } });
error.$mount("#error");
However it just gives me an error saying
_components_Alerts_danger__WEBPACK_IMPORTED_MODULE_3__.default is not a constructor
So I'm not sure how to fix this or do what I need to do. I've tried googling but can't seem to find an answer.
The Component imported is not a constructor and it should extends a constructor and to use that you should use Vue.extend()
Vue.extend() is a class inheritance method. Its task is to create a sub-class of Vue and return the constructor.
so instead of this
const error = new dangerAlert({ propsData: { text: "Error message" } });
error.$mount("#error");
make it like this
const DangerAlertExtended= Vue.extend(dangerAlert);
const error = new DangerAlertExtended({ propsData: { text: "Error message" } });
error.$mount("#error");

Passing component name to title field in Vue app

I have a Vue app like this:
<div id="app">
<Navbar/>
<div class="main">
<h1>{{ title }}</h1>
<router-view/>
</div>
<Foot/>
</div>
As I change pages via router-links, I'd like to also update the {{title}} field. The hacky way I've done it is this:
methods: {
logRoute() {
this.$nextTick(() => {
this.title = this.$route.name
});
}
}
However, sometimes I'd like to have the title be something different according to a property in the component, for example the "About" page is titled "About me." What's the best way to approach this?
Hi Jasper try this way.
Go to your route and and a meta on the router you want to have a title on like the code below
const routes = [
{
path: "/",
name: "Home",
component: Home,
meta: {
title: 'Home'
}
},
]
And go to your App.vue and add this a watch to look up when you go to different pages if you dont have a meta with a title it will put a default value on the website title.
export default {
watch: {
'$route' (to) {
document.title = to.meta.title || 'Default Title'
}
},
};
I hope this solves your problem have a nice day !

Experiencing navbar flicker with Vue.js

I'm experiencing a flicker in my navbar before a function is evaluated to either true or false.
The function that needs to evaluate is the following:
export default {
methods: {
isAuthenticated () {
return this.$store.state.user.authenticated
}
},
data: () => {
return {
unauthenticated: [
{
title: 'Link1',
url: '/link1'
},
{
title: 'Link2',
url: '/link2'
},
{
title: 'Link3',
url: '/link3'
}
],
authenticated: [
{
title: 'otherLink1',
url: '/otherlink1'
},
{
title: 'otherLink2',
url: '/otherlink2'
},
{
title: 'otherLink3',
url: '/otherlink3'
}
]
}
}
}
And the navbar has the following:
<template v-if="isAuthenticated()">
<b-nav is-nav-bar>
<b-nav-item v-for="nav in authenticated" :key="nav.title" :href="nav.url">{{nav.title}}</b-nav-item>
</b-nav>
</template>
<template v-else>
<b-nav is-nav-bar>
<b-nav-item v-for="nav in unauthenticated" :key="nav.title" :href="nav.url">{{nav.title}}</b-nav-item>
</b-nav>
</template>
However, when I click through the navigation, the unauthenticated links appear for a second and then the authenticated links appear as if the isAuthenticated() function hasn't evaluated yet. What can I do to remove this flicker?
My store file (user.js) file looks like this:
export const state = () => ({
headers: {},
profile: {}
})
export const mutations = {
updateHeaders (state, headers) {
state.headers.access_token = headers['access-token']
state.headers.token_type = headers['token-type']
state.headers.client = headers['client']
state.headers.expiry = headers['expiry']
state.headers.uid = headers['uid']
if (state.headers.expiry == null) {
state.authenticated = false
} else {
let timeToExpiry = new Date(state.headers.expiry * 1000)
let now = new Date()
state.authenticated = now < timeToExpiry
}
},
signout (state) {
state.headers = {}
state.profile = {}
}
}
The login/logout methods occur via API calls to a Rails app. The Devise gem handles the rest.
Thanks in advance!
EDIT:
I am using Nuxt.js for the layouts/pages/components so I believe that links submit with a this.$router.push(url) under the hood.
The b-nav tags are coming from Bootstrap Vue
When using bootstrap-vue there are two ways to add links to the navbar. One is to bind to :href attribute, which creates a regular html anchor. The other is to use :to attribute, which creates a link that interacts with vue-router.
<b-navbar-nav v-if="isAuthenticated()">
<b-nav-item v-for="nav in authenticated" :key="nav.title" :to="nav.url">{{nav.title}}</b-nav-item>
</b-navbar-nav>
<b-navbar-nav v-if="!isAuthenticated()">
<b-nav-item v-for="nav in unauthenticated" :key="nav.title" :to="nav.url">{{nav.title}}</b-nav-item>
</b-navbar-nav>
No reason to use <template> tags here to encapsulate the . Also note that 'is-nav-bar' is deprecated. See here where they note the deprecation.
What code executes when you click one of the links is not stated, I assume it's something like this.$router.push(url). If this is the case, you've probably have included your navbar in the <router-view>, so when you switch current route, components inside <router-view> rerender, so the navbar flashes. Move them out of the <router-view> should fix this.
edit: so the OP is not using vue-router yet, in this case, either manually change the root component's data to make parts other than the navs change, or add vue-router and use this.$router.push() to navigate so parts outside <router-view> won't change or flash.
Anyway, we need the vue component to stay to let vue to rerender only part of the view, while simply navigating by <a> or something will destruct everything and reconstruct them again, hence the flashing.