Can a component allow multiple ng-content with the same selector? - angular5

I am working on a component that serves as a "step by step form" but I do not know how to allow a component (stepper) to receive several contents (step) and be able to manipulate them.
An example of what I finally want is:
Stepper Component:
#Component({
selector: 'stepper',
template: `
<div class="stepper-container">
<ng-content select="step" #steps></ng-content>
</div>
`
})
And use like:
<stepper>
<step>Hola soy un step</step>
<step>Hola soy otro step</step>
<step>Y yo otro step</step>
</stepper>

Related

vue instance with child vue instance possible or alternative approach?

I would like to develop a vuejs multitouch app for a 4K display. It’s about 3-4 cards that are on a background and actually show the same content. For each of the cards a different entry page is visible.
Is it possible to pack several other instances (with the same content) of vuejs in divs within a Vue instance?
Somehow I would like to integrate an instance with store and router multiple times, but I can’t figure it out.
It would be helpful if someone can help me here, maybe provide a link or an approach.
I am looking for an approach how I can display the same content 3 times at the same time, at best with routes and nested routes. Each User can navigate separately, everyone has their own history via GUI.
when I try to use 2 instance inside the main vue instance 3 different routers, it’s always renders the content of main route.
I found this example where to instances are side by side, works great: https://jsfiddle.net/m91e7s2v/
but not inside a parent instance? why?
inside app.vue
<div id="app">
<VueToolMultitouch class="schatten" :startX="100" :startY="100" :startColor='"#00FF00"' id="id1" :idName="'id1'" :startZ="2">
<div id="subapp1">
<router-link to="/">/home</router-link>
<router-link to="/foo">/foo</router-link>
<p>Route path: {{ $route.path }}</p>
<router-view></router-view>
</div>
<h2>Passing Text 1</h2>
</VueToolMultitouch>
<VueToolMultitouch class="schatten" :startX="200" :startY="600" :startColor='"#FF0000"' id="id2" :idName="'id2'" :startZ="3">
<div id="subapp2">
<router-link to="/">/home</router-link>
<router-link to="/foo">/foo</router-link>
<p>Route path: {{ $route.path }}</p>
<router-view></router-view>
</div>
<h2>Passing Text 2</h2>
</VueToolMultitouch>
</div>
inside main.js
import router1 from "./router/router";
import router1 from "./router/router-1";
import router2 from "./router/router-2";
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
new Vue({
router: router1,
}).$mount("#subapp1");
new Vue({
router: router2,
}).$mount("#subapp2");
An alternative would be if everything is implemented with a single vue instance, but each of the cards gets its own "router".
maybe someone has an idea what that might look like.
The problem is that every child gets bound to the parent vue app and its prototype, this overrides the router of the children. I think that you'll need either to use iframes for the children or make the parent app handle with state the children views.
Edit:
I just learned about v-pre, this directive prevents Vue from "compiling" an HTML node and it's children.
You can basically have as many Vue instances even if they're nested as long as you put v-pre on the tag you use to mount the child Vue app.
Here's a working fiddle https://jsfiddle.net/dja36s7x/18/
I found an alternative way in the VueJS forum.
<div id="app">
<div class="row">
<my-child1></my-child1>
<my-child2></my-child2>
</div>
<div class="row">
<my-child3></my-child3>
<my-child4></my-child4>
</div>
</div>
const routes = [
{
path: '/page1',
component: { template: '<p>Page 1</p>' }
}, {
path: '/page2',
component: { template: '<p>Page 2</p>' }
}, {
path: '/page3',
component: { template: '<p>Page 3</p>' }
}
]
const MyChild = {
template: `
<div>
<router-link to="/page1">Page 1</router-link>
<router-link to="/page2">Page 2</router-link>
<router-link to="/page3">Page 3</router-link>
<button #click="$router.back()">Back</button>
<div>{{ $route.path }}</div>
<router-view />
</div>
`
}
function getChild() {
return {
extends: MyChild,
router: new VueRouter({
mode: 'abstract',
routes
})
}
}
new Vue({
components: {
MyChild1: getChild(),
MyChild2: getChild(),
MyChild3: getChild(),
MyChild4: getChild()
}
}).$mount('#app')
JSFiddle Example
Here, the components are expanded with their own router.
I currently no longer need the route via nested instances. but i will test the v-pre on everyone.
It seems this might be achieved using a hierarchy of components. If you're sure you need different Vue app instances, then it's worth going with Vue 3 as it's abandoned the idea of a shared global config, allowing you to create many Vue instances with createApp. All with different configurations.
You could do something like this (JS Fiddle here):
Vue.createApp({
name: 'App',
template: `
<h1>Primary App</h1>
<div id="subAppOne"></div>
<div id="subAppTwo"></div>
<div id="subAppThree"></div>
`
}).mount('#app');
Vue.createApp({
name: 'AppOne',
template: `<h2>App One</h2>`,
}).mount('#subAppOne');
Vue.createApp({
name: 'AppTwo',
template: `<h2>App Two</h2>`,
}).mount('#subAppTwo');
Vue.createApp({
name: 'App Three',
template: `<h2>App Three</h2>`,
}).mount('#subAppThree');
You can specify different routers with .use() on each app instance, just before calling mount().
const routerOne = VueRouter.createRouter({
history: VueRouter.createWebHistory(),
routes: [/* … */],
});
Vue.createApp({/* … */}).use(routerOne).mount('#appOne');

What is the best way to use Vuetify skeleton on Nuxt

I'm kinda new to Vue, Nuxt, and Vuetify and their aspects. I'm working on a Nuxt project with Vuetify and wanna use its skeleton loader but it's kinda messy. right now I use this pattern
template:
<v-skeleton-loader :loading="isLoading" type"card">
<mycomponent />
</v-skeleton-loader>
script
import skeleton from '#plugins/mixins/skeleton.js
export default {
mixins:[skeleton]
}
skeleton.js
export default{
data(){
return{
loading: null
}
},
computed:{
isLoading(){
return this.loading
}
},
created(){
this.loading = true
},
mounted(){
this.loading = false
}
}
when I first used it it was working perfectly. i had a static page and each of its components had their own skeleton and every time i loaded the page it would show their skeleton until they were loaded.
BUT.... as I started using this pattern on different pages i found out that it has many flaws!!
it only shows the skeleton when the page is refreshed!
won't show when I add components or data to the page! for example, an Axios call to get the product
it won't work when changing between routes
and so on ...
So, my question is, What's the best and most practical way to use the skeleton loader! i had a page with a v-for loop through a component and the component had its own skeleton in its template. it only show skeleton on refresh!
like this:
<div v-for="i in 10" :key="i">
<mycomp />
</div>
mycomp:
<v-skeleton-loader :loading="isLoading" type"card">
// components html codes
</v-skeleton-loader>
I would you suggest to create skeleton component. And in main component most of apps do this stuff, where the amount of skeleton is fixed or limited by pagination:
<template v-if="loading">
<skeleton v-for="i in 10" :key="i" />
</template>
<template v-else>
<div v-for="item in items" :key="item.id">
{{ item }}
</div>
</template>

Can I debug the export/import of a mixin?

I'm pretty new to vue.js and I'm trying to figure out how to use mixins.
I wondered if it is possible to create components which are bare of markup/template and contain only logic. As far as I understood, this should be possible and these components are called "mixins":
https://blog.bitsrc.io/understanding-mixins-in-vue-js-bdcf9e02a7c1
I'm using router functionality.
I'm now just trying out the vary basics of this concept and created the following:
listData1.vue, where the data for a list is created and then exported:
<script>
export default {
name: "listData1",
data() {
return {
list1: {
listData1A : "listData1A",
listData1A : "listData1B",
listData1A : "listData1C"
}
}
}
}
</script>
then listBuilder.vue, which takes the data and then uses it to create a list of items.
<template>
<div>
<ul>
<li v-for="element in list1" v-text="element"></li>
</ul>
</div>
</template>
<script>
import listData1 from "#/components/complexComponent2/listData1.vue"
export default{
name: 'listBuilder'
}
</script>
And then myComplexView2.vue in my views folder:
<template>
<div>
<h1>Second Awesome List!</h1>
<listBuilder />
</div>
</template>
<script>
import listBuilder from "#/views/myComplexView2.vue"
export default{
name: 'myComplexView2',
components: {
listBuilder
}
}
</script>
Now the result I get is this:
https://imgur.com/hQit785
But it should look like this:
http://localhost:8081/myComplexView
I'm a bit clueless what to do, especially since the vue dev tools in firefox don't show me much: https://imgur.com/RHJNy47.
Am I accessing the imported incorrectly?
Should I store the data differently, with the "data : {}" syntax or should I go for props in the listData component, like this:
props:["listData1"]
And then add the actual data in the component where the list is constructed with v-for? Though this would kind of undermine my goal to accomplish separating the data from the logic injecting it into the markup.
You need to setup listData1 as mixin in listBuilder.
<template>
<div>
<ul>
<li v-for="element in list1" v-text="element"></li>
</ul>
</div>
</template>
<script>
import listData1 from "#/components/complexComponent2/listData1.vue"
export default{
name: 'listBuilder',
mixins: [listData1],
}
</script>
Otherwise the ListBuilder won't have any data.
There's a typo in the mixin data:
listData1A : "listData1A",
listData1A : "listData1B",
listData1A : "listData1C"
Should be:
listData1A : "listData1A",
listData1B : "listData1B",
listData1C : "listData1C"
Apart from this, I don't see anything at syntax level in your code that would prevent mixin and v-for for working.
However, it puzzles me that myComplexView2 is importing myComplexView2.vue as the listBuilder:
import listBuilder from "#/views/myComplexView2.vue"
I don't know if this is an error you made when pasting to SO. Otherwise, the problem is probably here, since you need to import the listBuilder component, not the complex view.

Wrong component structure - prop-problems

I'm a noob and I'm trying to get my head around vue.js. In a particular route I have a view that looks like this
<template>
<div class="section">
<h1 class="title">Maintenance</h1>
<app-tabs></app-tabs>
<div class="columns">
<div class="column is-one-third">
<app-taglist></app-taglist>
</div>
<div class="column is-two-thirds">
<app-form></app-form>
</div>
</div>
</div>
</template>
<script>
import Taglist from "#/components/Taglist.vue";
import Tabs from "#/components/Tabs.vue";
import Form from "#/components/Form.vue";
export default {
}
</script>
Now I do understand the basics of passing data from a component to a child component, but what I'm actually trying to do is to pass data from app-tabs to app-taglist and from app-taglist to app-form. I'm starting to think that I'm attacking this all wrong, but if I do change my structure so that app-taglist is a child of app-tabs and app-form is a child of app-taglist - I can't really make proper use of the simple bulma, responsive, styling ...?
BTW: all components is registered globally at this time.
What kind of aproach would you advise me to look into - keeping in mind that I'm a noob.
Once you start getting to the point where you need to handle passing data between multiple components then I would consider using Vuex in order have a global component state that is accessible from all of your components.
Basically you can then create a totally separate "store" to hold your app's state (data):
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
And then from within each component, you can:
Use "getters" to read data from the store
Use "actions" to dispatch async functions that will "mutate" the store
e.g:
store.commit('increment') // this is a mutation
console.log(store.state.count) // -> 1

How to implement the navigating action of right click menu in Vue?

I am building a demo app, used for handling data. There is a lot of actions available. So I decide to implement a quick menu, which navigate the user to the detail panel, using the right click menu.
I try to use vue-router to mark all function with a unique path, like /action/info, /action/merge. But it turns out to be lack of management.
Are there any good way to solve it?
Vue-router makes sense to use if your actions demand a full screen. Otherwise, you can use a simple dialogue. But if you don't want to consider each action as a separate page, I see two options:
Option 1: You can use full-screen dialogues: you can show them without changing the route.
Option 2: You can use alternative navigation component that navigates without routes. It's not necessary to use it for the whole app. You can use it only for the page where you call all your actions. For example, take a look at v-ons-navigator from Onsen UI. It doesn't use routes, but a stack:
// Go to the "main" page by Vue-router and use v-ons-navigator inside to navigate
// between actions.
<template id="main">
<v-ons-navigator swipeable
:page-stack="pageStack"
#push-page="pageStack.push($event)"
></v-ons-navigator>
</template>
<template id="page">
<v-ons-page>
<v-ons-toolbar>
<div class="center">Page</div>
</v-ons-toolbar>
<p style="text-align: center">
This is the page
<v-ons-button #click="push">Action!</v-ons-button>
</p>
</v-ons-page>
</template>
<template id="action">
<v-ons-page>
<v-ons-toolbar>
<div class="left">
<v-ons-back-button>Page</v-ons-back-button>
</div>
<div class="center">Action!</div>
</v-ons-toolbar>
<p style="text-align: center">This is the page of the action</p>
</v-ons-page>
</template>
const action = {
key: 'action',
template: '#action'
};
const page = {
key: 'page',
template: '#page',
methods: {
push() {
// Here you go to the page of your action.
// You just push it in the stack without changing the route.
this.$emit('push-page', action);
}
}
};
const main = {
template: '#main',
data() {
return {
pageStack: [page]
}
}
};