Stencil #Element not finding child node - stenciljs

I have web component where i am trying to select a child node via the #Element property:
export class StepupVerification {
#Prop() token: string = 'test';
#State() url: string = `http://localhost:8080/?fail=${this.token}`;
#Element() private element: HTMLElement;
...
however, The query selector I am using on the item is returning zero children when I know the element exists. I know because I can find it with the same selector off of document.
Here is the selector I am using:
this.element.querySelectorAll('.stepup-frame');
as I said, it returns zero elements. however when I use:
document.querySelectorAll('.stepup-frame');
I am finding the element fine.
TL;DR: querySelector on an element is not working correctly for my webcomponent, and I am not sure why.

I was really looking to use the ref functionality to get references to embedded elements.
i was able to add a private myElement: HTMLElement variable to my component, and then reference it via this.myElement within my code.

Related

Vue - Emit Child to parent

In a vue2 application i need to send a value from a child to the parent. I try something like this
Child function
goTo(id: string) {
this.$emit('goToSpots', id)
},
Parent Component
<Main
class="px-5"
#goToSpots="goToSpots()"
/>
Parent function
goToSpots(id: string) {
this.selected = id
},
The problem: this.selected returns undefined, can't get param properly.
The question is: Whats is the proper way to send params?
In your HTML template, use
#goToSpots="goToSpots($event)"
or
#goToSpots="goToSpots"
instead. At the moment, you are not passing any argument to the function. If you don't add brackets at all, the parameter is automatically added and if you use brackets, you can pass the reserved variable $event which contains the emitted data.

VueJS Use VNode inside render function with createElement?

I am trying to render a Vnode inside my render function. In such a way that I can still give that element children.
I know you can have an array of Vnodes as the third argument of createElement(tag, data, vnode[]) but since I want to give this specific Vnode children still I seem to be a little stuck,
I have tried doing something like:
const vnodeObj = {tag: vnode.tag, data: vnode.data}
//Skip to inside render function
createElement(vnodeObj.tag, vnodeObj.data, []).
Which worked well to create the tag but I have found that the data object returend from Vnode.data is not the same for the data object createElement expect for example:
If I were to add a class "test" and a ref "test2" to a element using create element the data object would look like so:
{
attrs: { class: "test", ref: "test2"},
}
while the Vnode.data would return something like:
{
"ref":"test2",
"staticClass":"test"
}
Leading me to believe there must be a better way to render a single Vnode and its data and continue giving it children with createElement.

VueJS find element by key

I've just wanted to know if it is possible to find a DOM element by the key attribute of vue?
I'm currently working with a list. I'm displaying it via v-for directive on a div. I'm binding the key with the index of the elements.
v-for="(apk, index) in project.apks" v-bind:key="index"
It would really help me if i could compute something for each of these elements as soon as they are fetch from my server and displayed. It's just parsing a file and looking for keyword, and accordingly choosing a css class for the items.
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
The purpose of key is not selecting element. Even if it can be done, don't do it.
The proper way to do it is by using ref.
for example, add ref attribute to your html like this
v-for="(apk, index) in project.apks" v-bind:key="index" :ref="'sample-ref-'+index"
and then in your methods, you can get the DOM using this.$refs['sample-ref-0'],this.$refs['sample-ref-1'] and so on.
Hope this helps.
I found that if you give the 'ref' the same name in a v-for, like this:
<div v-for="data in list" :key="data.id" ref="bar"></div>
Then you will find they just store in an array called 'bar' and you can visit them by:
this.$refs['bar'][index]
something like this could allow you to find a component by key :
this.$children.forEach(child=>{
print("child.$vnode.key")
})
also use mounted , as it gets called when the component is added to the dom:
mounted:function(){
this.$el.querySelector("#ele1")...
}
The problem is I dont know how to call a method for each of these elements as soon as they are added to the DOM. They are a lot of html events but i couldnt find one representing the object beeing inserted to dom :(
You can create a new component with your v-for and just call the created() hook.
Example
/* On your main function */
<div v-for="apk in project.apks">
<apk :data="apk"></apk>
</div>
/* On your 'apk' component */
export default {
props: [ "data" ],
created() {
console.log("Created !");
}
}

Pass Function as Property to Vue Component

I am trying to make my Vue Component reusable but there is a part in it which requires to run a function on button click which I have defined in the parent component.
The component's button will always run a parent function and the parameter it passes is always the same (its only other property).
Right now I am passing 2 properties to the component: 1) an object and 2) the parent function reference, which requires the object from 1) as a parameter.
The Child-Component looks like this (stripped unnecessary code):
<button v-on:click="parentMethod(placement)">Analyze</button>
Vue.component('reporting-placement', {
props: ['placement', 'method'],
template: '#reporting-placement',
methods: {
parentMethod: function(placement) {
this.method(placement);
}
}
});
The parent is making use of the child like this:
<reporting-placement v-bind:placement="placement" v-bind:method="analyzePlacement"></reporting-placement>
methods: {
analyzePlacement: function(placement) {
this.active_placement = placement;
},
}
As you can see, the child has only one property, placement, and the callback reference. The placement must be put in as a parameter to the reference function from the parent.
But since the parent defines the parameters, the child shouldn't concern itself with what it needs to pass to the parent function. Instead I would prefer to already pass the parameter along in the parent.
So instead of
<reporting-placement v-bind:placement="placement" v-bind:method="analyzePlacement"></reporting-placement>
I would prefer
<reporting-placement v-bind:placement="placement" v-bind:method="analyzePlacement(placement)"></reporting-placement>
(including appropriate changes in the child).
But passing the parameter along does not work that way.
Is it possible (maybe in other syntax) to 'bind' the variable to the function reference so that it is automatically passed along when the callback is called?
Info: I don't get an error message if I write it down as above but the whole Vue screws up when I pass the parameter along to the component.
Hope the issue is clear :-) Thanks a lot!
By reading your proposal I've found out that you are overusing the props passing.
Your concern that child component should not have any knowledge about the way that the parent component uses the data is completely acceptable.
To achieve this you can use Vue's event broadcasting system instead of passing the method as props.
So your code will become something like this:
Vue.component('reporting-placement', {
props: ['placement', 'method'],
template: '#reporting-placement',
methods: {
parentMethod: function(placement) {
this.$emit('reporting-placement-change', placement)
}
}
});
And you can use it like this:
<reporting-placement v-bind:placement="placement" #reporting-placement-change="analyzePlacement($event)"></reporting-placement>
But if you need the data which is provided by the method from parent it's better to consider using a state management system (which can be a simple EventBus or event the more complex Vuex)
And finally, if you really like/have to pass the method as a prop, You can put it in an object, and pass that object as prop.

Cannot observe property [] of Object

I have a custom component that has an items property, defined as #children for the component:
#children(`${ComponentConfiguration.prefix}tracker-item`) items = [];
tracker-item is a simple view-model with a #noView annotation, and has only one property.
The items are defined in my view like this:
<tracker-item label="${trackerElementModel.steps[0] | displayDate:'DD MMMM'}"> ${"PURCHASE.RQT_DTE" | t} </tracker-item>
This worked perfectly, but after I updated my project in order to build it with aurelia-cli, I see this error every time the component is called:
WARN [property-observation] Cannot observe property 'items' of object
TrackerComponent {_isAttached: false, _taskQueue: TaskQueue, _useTaskQueue: true, _alertService: AlertService, parentElement: null…}
TrackerComponent is the name of my custom component.
I don't understand where that error comes from, because somewhere else in my code I have the same definition for another custom component which don't raise the same error.
What is wrong with this?
I managed to get rid of the warning on my custom element.
Apparently, this only happens when you use #children annotation at a property level. If you move the annotation to a class level the warning should go away. In your case the class level annotation would look something like this:
#children(name: 'items', selector: `${ComponentConfiguration.prefix}tracker-item`)
export class <yourClass> {
...
}