Angular2 recursive component output - recursion

I have following problem:
let's assume that I have Component A that have two subcomponents Ar and Ad. Subcomponent Ar is recursive created tree and subcomponent Ad is component which shows details about choosen node in recursive tree (subcomponent Ar). How can I send selected node from sub(sub)component in Ar to Component Ad using #Output? Should it be #Output or something else?
app.component.html:
<tree [input]="fooTree" [output]="updateDetails($event)"></tree>
<tree-details [input]="input"></tree-details>
tree.component.html:
<tree [input]="fooTree.children"></tree>
tree-details.component.html
<div>{{input.name}}</div>
<div>{{input.id}}</div>
In this case I will see only root tree details, how can I do this to get info from other node (one of recursivly created), when is selected?

UPDATE:
Its easier to see in a demo-app: https://plnkr.co/edit/WaYluZyPaC0OEV0YovbC?p=preview
..
Your tree-component Ar could have an #Ouput().
Your AppComponent would consume this output and would post the selected data to the second sub-component detail-component.
app.component.html
<tree (yourOutputNameHere)="yourFunctionToReceiveAndPostSelectedData($event)"></tree>
<details #yourDetailViewComponent></details>
tree.component.html
<tree (yourOutputNameHere)="yourFunctionToReceiveAndPostSelectedData($event)"></tree>
Your tree-component could even have an #Input() and inside of your template you could do something like this:
app.component.html
<tree [detail-view-input]="yourDetailViewComponent"></tree>
<details #yourDetailViewComponent></details>
tree.component.html
<tree [detail-view-input]="detailViewInput"></tree>

Related

How to manually mount more than one component into the same DOM node in vue3?

Just like the title, I try to use the createapp method to build component objects, and then mount to DOM nodes. When there are multiple mounts, all the previous ones are cleared. How can I mount continuously while retaining the previous node, just like "insertAfter" in jQuery.
You can do multiple mounts as below.
index.html in body tag
<body>
<div id="header"></div>
<div id="section1"></div>
</body>
main.js file or other file where you mount app.
const headerApp = createApp({
/* ... */
})
headerApp.mount('#header')
const sectionApp = createApp({
/* ... */
})
sectionApp.mount('#section1')

How to not display subcomponent if it's empty without using *ngIf in it's parent?

I have a following problem:
There is a Component A with a Subcomponent B.
<app-alert [response]="alertMessage"></app-alert>
Subcomponent B extends Ngb-alert component and has an template like:
<ngb-alert #selfClosingAlert id="selfClosingAlert" *ngIf="alertMessage" [type]="alertStyle" (closed)="alertMessage = ''">
{{ alertMessage }}
</ngb-alert>
When the alertMessage is empty alert is hidden but my Subcomponent B tag still takes up some space on the site. Generally I want Subcomponent B to be self-responsible. I searched a lot for the answer but found nothing.
I solved it this way:
Added host class condition on my alertMessage value in Subcomponent B component decorator
#Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.css'],
host: {
'[class.d-none]': 'alertMessage === ""',
}
})
So when alertMessage is empty, my Subcomponent B tag gets .d-none (bootstrap) class which sets it's display to 'none'. Now it doesn't take up any place when the alertMessage is empty.

Can you use decorators with storybook for html in CSF format?

I'm trying to use decorators in CSF format. I tried this example in the documentation, but since it's written for React, it didn't work for me.
export default {
title: 'My Component',
decorators: [(Story) => <div style={{ margin: '3em' }}><Story/></div>]
}
Is it currently possible to use decorators on a component or story level for html?
In CSF, a story is a function which return a "story object". this object is rendered by a renderer dependant of the framework used.
A decorator is just another function which take a story, and generate the object to render. This notion is global, and works with all supported framework.
With the html framework, the "story object" is just a String to be rendered with innerHtml. So a valid decorator for the html framework is a function, which take as the first argument a story function, and return a string.
decorators = [(story) => `<div style="margin: 3em">${story()}</div>`]

Css Selector in Framework7 vue

i try to build an Cordova/Phonegap application using vue.js and the Framework7.
I find out how to use functions like "onClick" using the "v-on:click="OnClick" attribute in an html element. Framework7 has jquery already implemented in the dom.
But there is one question. How can i access the dom directly, so that i can select whole css classes with the jquery selector. Like:
$('.likeButton'). ?
In the offical framework7 i found something like this to access the dom with its functions:
this.$$ or this.Dom7
This is what i have already written down in the home.vue file:
<script>
//import Fonts-awesome Icons
import FontAwesomeIcon from '#fortawesome/vue-fontawesome'
import {} from '#fortawesome/fontawesome-free-solid'
import F7Icon from "framework7-vue/src/components/icon";
import F7PageContent from "framework7-vue/src/components/page-content";
import * as Framework7 from "framework7";
export default {
name: 'FAExample',
components: {
F7PageContent,
F7Icon,
FontAwesomeIcon
},
methods: {
clickit: function () {
console.log("hi");
//this is what i have tested, looking if i have access to dom
let $$ = this.$$;
console.log($$);
},
//this is what i want to use
$('.likebutton').on('click',function () {
})
}
}
</script>
Did any of you have an idea how this works?
I hope you can help me. I'm new with vue.js in combination with the framework7.
Thank's for your help :)
We can use all the DOM functions just like
this.$$('.classname)
for example, if you want to hide something by jquery you can use as:
this.$$('.classname).hide()
To check all the DOM functions you can check the official documentation.
https://framework7.io/docs/dom7.html
But make sure that your DOM function should not in any Window function.
If you get the error to implemented it, just make the 'this' instance first.
Just like:
var self=this; // a global variable with this instance
use
self.$$('.classname).hide()
for any framework7 help, just ping me on skyp: sagardhiman5_1
Have you tried using Vue's $refs? You can set a reference to a specific DOM element and then access that in Vue.
A simple example:
<template>
<div class="some-item" ref="itemRef">Some item</div>
</template>
Then in the component:
var myItem = this.$refs.myItem;
// do what you want with that DOM item...
You can also access $refs from the parent. The example in the link below gives details on that.
More on $refs: https://v2.vuejs.org/v2/guide/components.html#Child-Component-Refs

Vue 2.0 Laravel 5.3 Parent Child relationship with slot

I have a project where when i click on a anchor on parent item-sorting-list a property of child item-card will change so it sort something out based on that property. However the data does not seem to pass to the child. I am wondering if there is anything wrong when i built up the parent child relationship in the meanwhile?
template (item-sorting-list)
<a :name="subcat.name" href="" #click.prevent="getSelectedSubcat(subcat.name)">{{subcat.name}}</a>
methods (item-sorting-list)
methods: {
getSelectedSubcat(subcat){
var vm = this;
vm.selectedSubcat = subcat
}
}
When I click on the subcat.name, it does actually store subcat.name into selectedSubcat (verified from Vue devtool) in the item-sorting-list component. The problem is item-card does not store it even though i put selectedSubcat as props
HTML (does this work as parent child relationship here?)
<item-sorting-list><item-card></item-card></item-sorting-list>
UPDATED item-card
export default {
props:[
'selectedSubcat'
],
data(){
return {
products:[],
}
},
mounted() {
this.getAllProducts()
},
methods: {
getAllProducts(){
var vm = this;
vm.$http.get('/getProducts').then((response)=>{
vm.products = response.data.data.products;
});
}
}
}
from Vue devtool, item-card is included in the item-sorting-list, I would say that means they are parent child relationship? but then when i click something in item-sorting-list and change selectedSubcat, selectedSubcat in item-sorting-list does change but the selectedSubcat in item-card remains undefined. Sorry for my bad English.
UPDATE2
I notice that every example that I found online is that they set selectedSubcat in the new Vue with el="#app" in it instead of any other component (in my case item-sorting-list). Does that matter? I feel like the :selected-subcat="selectedSubcat in
<item-sorting-list>
<item-card :selected-subcat="selectedSubcat"></item-card>
</item-sorting-list>
cannot read the selectedSubcat that I defined in the component item-sorting-list but instead if i set selectedSubcat in the following
const app = new Vue({
el: '#app',
data:{
selectedSubcat:1
}
});
it does read selectedSubcat as 1. So what I would say is that item-card does not consider item-sorting-list as its parent. But why and how can I make it to become item-card's parent? [NOTE: but in the Vue devtool the tree does show that item-sorting-list does consist of item-card, item-card does show after clicking the arrow on the left of item-sorting-list]
In VueJs, you have parent child relation, when you don't register a vue component globally, but you make a component available only in the scope of another instance/component by registering it with the components instance option, like following:
var Child = {
template: '<div>A custom component!</div>'
}
new Vue({
// ...
components: {
// <my-component> will only be available in parent's template
'my-component': Child
}
})
In your case, I dont see selectedSubcat being passed as dynamic props to child component item-card. Dynamic props to data on the parent ensures whenever the data is updated in the parent, it will also flow down to the child:
You probably have to pass it to child like following:
<item-sorting-list>
<item-card :selected-subcat="selectedSubcat"></item-card>
</item-sorting-list>
You also have to add props in your item-list like this:
var itemList = {
props: ["selectedSubcat"]
template: '<div>Yout component!</div>'
}
notice I have converted it to kebab-case, because HTML being case-insensitive, camelCased prop names need to use their kebab-case (hyphen-delimited) equivalents(Documentation).

Resources