Dynamically add navigation items in Vue CoreUI - javascript

In my project, I want to add some Ajax loaded menu items to my CoreUI sidebar in Vue. I already found a working solution, but it's kind of hacky and might have timing issues. Therefore I want to ask you, if there is a proper or at least better solution.
I also found this question from a few days ago, but it doesn't have an answer yet.
// main.js
new Vue({
el: '#app',
router,
icons,
template: '<App/>',
components: {
App
},
data: {
clientConfiguration: null
},
created: async function () {
let svcResult = await this.$http.get('Picking/ViewerSettings');
this.clientConfiguration = svcResult.data;
this.$children[0].$children[0].$children[0].$data.nav[0]._children[0].items =
svcResult.data.map(vc => ({
name: vc.name,
to: 'test/' + vc.name,
icon: 'cil-spreadsheet'
}));
}
})
// _nav.js
export default [
{
_name: 'CSidebarNav',
_children: [
{
_name: 'CSidebarNavDropdown',
name: 'Lists',
to: '/test',
icon: 'cil-list-numbered',
items: []
},
// ...
]
}
]

The _nav.js file is just an example of data structure that can be rendered by CRenderFunction component docs
The idea behind CRenderFunction is that you can render components from the Array/Object.
In your case, you have two options:
generate CRenderFunction object on backend,
generate CRenderFunction object on frontend by computed properties, based on data you got from the backend
Here is the example of the second approach:
in template
<CRenderFunction flat :content-to-render="navItems"/>
in script:
//example array that you receive from backend
const menuItems = [
{
name: 'first item',
to: '/first',
icon: 'cil-user'
},
{
name: 'second item',
to: '/second'
},
{
name: 'third item',
to: '/third'
}
]
export default {
computed: {
navItems () {
return [
{
_name: 'CSidebarNav',
_children: this.sidebarNavChildren
}
]
},
sidebarNavChildren () {
return menuItems.map(menuItem => {
return {
_name: 'CSidebarNavItem',
name: menuItem.name,
to: menuItem.to,
icon: menuItem.icon || 'cil-spreadsheet'
}
})
}
}
}
navItems computed property result:
[{"_name":"CSidebarNav","_children": [
{"_name":"CSidebarNavItem","name":"first item","to":"/first","icon":"cil-user"},
{"_name":"CSidebarNavItem","name":"second item","to":"/second","icon":"cil-spreadsheet"},
{"_name":"CSidebarNavItem","name":"third item","to":"/third","icon":"cil-spreadsheet"}
]
}]

Related

How make dynamic breadcrumbs in vue.js?

I would like to have a dynamic breadcrumbs based on where I clicked on a category but I get an error that says my variable is undefined: TypeError: Cannot read properties of undefined (reading 'homeMenu'). Yet in my getHomeCategory function, the console.log of homeCategory displays Perma'Thèque. I don't understand how to do it, thanks
Here is the code :
<script>
export default {
props: {
},
data: () => ({
homeMenu: "",
breadcrumbs: [
{
text: 'Accueil',
disabled: false,
href: '/',
},
{
text: this.homeMenu,
disabled: false,
href: "/" + this.homeMenu,
},
],
}),
computed: {
...mapGetters({
console: () => console,
homeCategory: 'home/getCategory',
})
},
methods: {
getHomeCategory () {
if (this.homeCategory === "Perma'Thèque") {
console.log(this.homeCategory)
return this.homeMenu = "permatheque"
} else {
return this.homeMenu = "null"
}
},
},
mounted() {
if (this.plantActive) this.loading = false;
this.getHomeCategory()
}
}
</script>
data() is declared here as an arrow function, so this refers to the outer scope, not the Vue component instance, but even as a regular function here, this.homeMenu won't yet exist.
It seems that you actually want breadcrumbs to be reactive to homeMenu, so you should move breadcrumbs to a computed prop:
export default {
data: () => ({
homeMenu: '',
}),
computed: {
breadcrumbs() {
return [
{
text: 'Accueil',
disabled: false,
href: '/',
},
{
text: this.homeMenu,
disabled: false,
href: '/' + this.homeMenu,
},
]
}
}
}
demo
I used Element Plus UI and my mind was blown. Check out my blog and the codes. Element Plus is a free library that is great for Vue JS. They have very nice UI for breadcrumb and can be implemented with v-for loop.
https://medium.com/#samchowdhury/create-a-breadcrumb-with-vue-js-and-element-plus-ui-f3e2fde50a3e

How to update head title after axios call in vue js

I have a product page where i pass product id & based on that i call rest Api & after Api response i need to update title tag with product name. i am able to update title tag but in view source i get value as undefined or default value. So how to update title in the beginning so will get product name in view source. So that will be SEO friendly.
export default {
name: 'App',
components: {
HelloWorld
},
data () {
return {
setTitle: {}
}
},
created () {
axios.get('https://apiurl.com/testing.json')
.then((response) => {
this.setTitle = response.data
})
},
metaInfo() {
return {
title: `${this.setTitle.product_name} product name`,
meta: [
{
vmid: "description",
name: "description",
content:
"hello world, this is an example of adding a description with vueMeta"
}
]
}
}
}
Is it possible if in my project SSR is false?
You should use asyncData hook provided by nuxt which runs before creating the page (you don't need to define setTitle in data option ) and replace metaInfo by head :
export default{
name: 'App',
components: {
HelloWorld
},
async asyncData() {
const {data} = await axios.get('https://apiurl.com/testing.json')
return { setTitle:data} // without defining data option
},
head() {
return {
title: `${this.setTitle.product_name} product name`,
meta: [
{
vmid: "description",
name: "description",
content:
"hello world, this is an example of adding a description with vueMeta"
}
]
}
}
}

Testing component - Error in mounted hook: "TypeError: Cannot read property 'dispatch' of undefined"

I am trying to write a simple test for my vue component. Since the vue component makes an async call on mount and updates the vuex store, dispatch is called during mount, which breaks my existing unit tests. Any idea how to overcome this? Since I am mocking table data, I don't need the mounted() function to be called when running the tests.
MyTable.spec.js
const wrapper = shallowMount(MyTable, {
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});
...
MyTable.vue
...
data() {
return {
options: {
...
}
};
},
methods: {
getHeadings() {
let headings = {};
this.columns.map((key, i) => headings[key] = this.headings[i]);
return headings;
},
setColumnClasses() {
let classes = {};
this.columns.map((key) => classes[key] = key);
return classes;
},
loadRecords(actionType) {
this.$store.dispatch(actionType);
}
},
props: {
tableData: {
type: Array,
required: true
},
columns: {
type: Array,
required: true
},
actionType: {
type: String,
required: true
},
headings: {
type: Array,
required: true
},
...
},
mounted() {
this.loadRecords(this.actionType);
}
You are getting this error message because Vue (when mounted) is expecting that the this.$store is defined, and while it might be within your application, you are not importing it, nor are you mocking it.
Here is your test function code you provided:
const wrapper = shallowMount(MyTable, {
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});
Here is what you need to add:
import store from '../path/to/store.js';
import { createLocalVue, shallowMount } from '#vue/test-utils';
// You will want to create a local Vue instance for testing purposes: https://vue-test-utils.vuejs.org/api/#createlocalvue
const localVue = createLocalVue();
// This tells the local Vue instance to use Vuex for the store mechanism.
localVue.use(Vuex);
const wrapper = shallowMount(MyTable, {
localVue, // Bind the local Vue instance when we shallow-mount the component.
store, // Bind the store so all of the methods are available when invoked.
propsData: {
tableData: [
{
"product_id":10826345236,
"name":"T-Shirt"
}
],
columns: ['product_id', 'name'],
headings: ['Product ID', 'Name'],
actionType: 'loadProducts'
}
});

how to vue-json-to-csv with vue

Good afternoon everyone I'm having a problem converting json to csv, I'm using a lib I found at https://github.com/angeliquekom/vue-json-to-csv, to be very interesting, but I'm having trouble passing an arrau for component.
my code:
<template>
<vue-json-to-csv :json-data="data"
:labels="{
id: { title: 'id' },
co_tipo_nota: { title: 'co_tipo_nota' },
ds_nota: { title: 'ds_nota' },
ds_outro_criterio: { title: 'ds_outro_criterio' },
ds_nofl_avaliacao_anonimata: { title: 'fl_avaliacao_anonima' },
dt_nota: { title: 'dt_nota' },
}"
#success="val => handleSuccess(val)"
#error="val => handleError(val)">
<button>
<b>My custom button</b>
</button>
</vue-json-to-csv>
</template>
<script>
import VueJsonToCsv from 'vue-json-to-csv'
import { baseApiUrl } from '#/global'
import axios from 'axios'
export default {
name: 'DowloadCvsThree',
components: {
VueJsonToCsv,
},
data: function() {
return {
mode: 'save',
nota: {},
notas: [],
}
},
props: {
notas: Array
},
methods: {
loadUsers() {
const url = `${baseApiUrl}/notas`
axios.get(url).then(res => {
this.notas = res.data
})
},
mounted() {
this.loadUsers()
}
}
}
</script>
<style>
</style>
the error return is ?
[o erro][1]
[1]: https://i.stack.imgur.com/llHeZ.png
can anybody help me? I'm trying to pass an array to the json-to-csv: json-data = "data" component, but the date is not an array with I do?
he address of lib npm is: https://github.com/angeliquekom/vue-json-to-csv
awaiting return?

Pass object to Angular2 Component using Router

I'm poking Angular2 and it's Routing system. I'm creating 'Project Wizard' #Component with 'child' #Components using #RouteConfig and it looks like this:
const enum State {
welcome, basicData, groupsData, overview
}
const enum Condition {
back
}
#Component({
selector: 'router-outlet',
templateUrl: '/app/templates/wizard/project/project-wizard-container.html',
directives: [
ROUTER_DIRECTIVES,
],
})
#RouteConfig([
{ path: '/', name: 'ProjectWizardWelcome', component: ProjectWizardWelcomeComponent, useAsDefault: true },
{ path: '/step2', name: 'ProjectWizardStep2', component: ProjectWizardStep2Component },
{ path: '/step3', name: 'ProjectWizardStep3', component: ProjectWizardStep3Component },
{ path: '/overview', name: 'ProjectWizardOverview', component: ProjectWizardOverviewComponent },
])
export class ProjectWizardComponent {
mock: Mock = new Mock();
private mapping: {key: State, value: string}[] = [
{ key: State.welcome, value: 'ProjectWizardWelcome' },
{ key: State.basicData, value: 'ProjectWizardStep2' },
{ key: State.groupsData, value: 'ProjectWizardStep3' },
{ key: State.overview, value: 'ProjectWizardOverview' },
];
private transitions: FSM.Transition<State, Condition>[] = [
{ from: State.welcome, conditions: [], to: State.basicData },
{ from: State.basicData, conditions: [Condition.back], to: State.welcome },
{ from: State.basicData, conditions: [], to: State.groupsData },
{ from: State.groupsData, conditions: [Condition.back], to: State.basicData },
{ from: State.groupsData, conditions: [], to: State.overview },
{ from: State.overview, conditions: [Condition.back], to: State.groupsData },
];
private fsm: FSM<State, Condition> = new FSM(State.welcome, this.transitions);
constructor(
private _router: Router,
private _routeParams: RouteParams) {
}
onPrev(): void {
var prevState = this.fsm.apply([Condition.back]).get();
var prevRoute = this.mapping[prevState].value;
this._router.navigateByInstruction(this._router.generate([prevRoute]), true);
}
onNext(): void {
var nextState: State = this.fsm.apply([]).get();
var nextRoute = this.mapping[nextState].value;
this._router.navigateByInstruction(this._router.generate([nextRoute]), true);
}
onCancel(): void {
this._router.navigate(['Welcome']);
}
}
I need to share a Mock object across 'child' components and I want to understand what my options are. My current understanding is that:
it can be shared using container object which is #Injectable like some Service.
using RouterData. In this case, I would need to unmarshal data from url.
But are there any other ways to pass this object to #Components directly using router?
No, these two are the available options. I'd suggest a shared service.

Categories