How to pass data from one child to parent and other child components? - angular5

I have divided my page into following format. I have a parent component and multiple child components. First one being the filter component. So when I make a submit in this component its result is to be implemented in all other child component as well as in parent component too.
I think of as the date I receive from child-A to parent component pass it to child-B and child-C but I couldn't fix it.
I am working here:
https://stackblitz.com/edit/angular-fqp5px
Can anybody help me on this?
Thank You.

You can just create simple service and pass value to Subject object. And subscribe that object in other component where ever you want to make use of it.
For example service:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import { Subject } from 'rxjs';
#Injectable()
export class dataService {
//here i am giving example for string. You can use any kind of object(class)
private querySource = new Subject<string>();
query$ = this.querySource.asObservable();
functionname(value: string){
this.querySource.next(value);
}
}
Now subscribe this service and call functionName function on submit button. And the change will be subscribed where ever you want it in parent or any other child component.
For refrence go through this

Related

What are the best practices for object props in VueJS?

I have a Vue Component that is a form for creating (or editing) a patient. It contains a lot of information: birthname, firstname, date of birth, birth place, gender, etc.
What are the best practices in terms of maintainability, reactivity and performance to pass those information?
Is this recommended to pass each information item as a prop?
<patient-form
:firstname.sync="patient.firstname"
:lastname.sync="patient.lastname"
:birthdate.sync="patient.birthdate"
... />
Or more recommended to use an object Patient with all the information?
<patient-form :patient="patient" #update="updatePatient"/>
Personally, I prefer the second approach. It looks cleaner. Whenever you want to add a new property like age you don't have to worry about adding it both in the parent and the child component the object finishes the job. And reactivity wise toRefs can handle it like this.
Or simple snippet
<script setup>
import { toRefs, defineProps } from 'vue'
const props = defineProps({
patient: {
type: Object
}
})
const { patient } = toRefs(props)
But there is also another way in addition to illustrated in the comment section. Let me guess you are fetching the data from server, so you can just pass the id of the patient and fetch inside your child component.
Your requirement is totally depends on the use case of <patient-form> component and the data you are using in this component.
If you have multiple reference of <patient-form> in a parent component. i.e in case of edit the parent information against each parent record. In this case, I will suggest to get the real time parent information from a database through an API call in the child component itself.
Hence, As per my understanding the best approach would be, pass the parent id as a prop in the <patient-form> component and then get the real time updated data by calling an API based on patient id and bind the response in the template. Then on successful edit, you can post the data and emit the success event to parent.
In parent component :
<patient-form :patientid="patient.id" #update="isUpdateSuccess"/>
In child component :
mounted() {
// get parent data based on the `patientid` parameter and bind that in the template.
}
methods: {
onUpdate(id) {
// post the updated data with the help of an API call.
// emit the success event on parent else show the error in the child itself.
}
}
But if still you already have the patient data in your parent component and you want to pass that in the <patient-form> component, Then your second solution is better than the first one. Go for that.

How to loop over an array of objects and display it in UI using angular 8

I am trying to loop over an array of objects and display it in html using Angular 8.
My app.component.ts file is as shown below:
In the above code uptimeDataSet is the array of data that I need to loop over and display on another component.
My app.component.html file looks as shown below:
Finally, I am trying to loop over in my component to display the object in uptime-chart-component.html as below:
But I am not able to get the details in the UI. I am not able to find out where I am going wrong. Can someone please help me with this.
Update your uptime-chart.component.ts file-
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-uptime-chart',
templateUrl: './uptime-chart.component.html',
styleUrls: ['./uptime-chart.component.css']
})
export class UptimeChartComponent implements OnInit {
#Input() chartData: any[];
constructor() { }
ngOnInit(): void {
}
}
You need use #Input to capture the value in your child component. #Input decorator is used when you are passing data from parent to child. I suggest you take a look at this blog to understand- https://fireship.io/lessons/sharing-data-between-angular-components-four-methods/
And I believe, you can change your app.component.html without the *ngFor-
<app-user [chartData]="uptimeDataSet"></app-user>
if this is what you want your result to be

VUE js call a child component method in a different component hierarchy

I have this following vuejs component hierarchy.
What i want to do it to invoke COMP_B_ONE validate() method, when COMP_A_TWO submit() method is invoked EVERY TIME.
MAIN_COMPONENT
COMP_A_ONE
COMP_B_ONE
validate()
COMP_B_TWO
validate()
COMP_A_TWO
submit()
I've already implemented an emit when submit is triggered in COMP_A_TWO which can be listened in MAIN_COMPONENT
submit() {
this.$emit('submit')
}
what seems to be the best approach in this regard? any suggestions appreciated.
I can get this done by two ways.
1 - Global EventBus
I will create an eventBus and register events on it from any file and listen it anywhere -
import { EventBus } from '#/eventBus'
// simply import it to component which need listen the event
//Register Event where you have your methods - like In your COMP_B_TWO
EventBus.$on('validate', () => { this.validate() })
// Emit event from another component
EventBus.$emit('validate')// Like directly from your COMP_A_TWO
To know how to create a eventBus follow this - Global Event Bus Vue
Another way I can think is
2 - Refs
Add reference to COMP_A_ONE like
<COMP_A_ONE ref = "one" />
Then add reference to COMP_B_ONE
<COMP_B_ONE ref = "b-one" />
Now when you trigger submit from main component
execute it -
this.$on('submit', () => {
this.$refs.one['b-one'].validate()
})
It totally depends which way you wanna go -
If you need to call validate for many more places, I would suggest choosing EventBus
You just need current component to have it, use Refs

What is the name of my Vue component?

I'm trying to use Vue for a little project.
I started with only client code. So when I did
const mv = new Vue({...});
I was able to access to the component from outside with a mv.
Now I'm using Vue.cli, so I define my component inside a mv.vue and then I have
export default {
data () {}
}
Here, how can I get the nme of my component?
Thanks for any reply or hint :)
You can get the name of the component , you can do this
this.$vnode.tag
If you want the parent component's name from its child do this
this.$parent.$vnode.tag
You can name your component like so:
export default {
name: 'mv',
data () {
return {}
}
}
But to access it you'd need to use the name that you import it with. For example:
import theVariableIWantItToBe from './mv.vue'
console.log(theVariableIWantItToBe)
To expand on the very good #vamsi-krishna answer, and update it, I've discovered that Vue now often puts a prefix on the $vnode.tag along the lines of vue-component-3-YourComponentName.
You can fix this by using the following code. And perhaps, just in case of a missing tag, fall back to the ID of the root element in the component.
Occasionally, Vue doesn't pass back a component at all in its errorHandler and warnHandler global events. So I've handled that scenario first.
if (!vm){
return '[unknown]'
}
if (vm.$vnode.tag) {
const res = vm.$vnode.tag
return res.replace(/vue-component-\d+-/i, '')
}
if (vm.$el.id) {
return vm.$el.id
}

How to set a parent property from within a custom element in Aurelia?

A few days ago I asked this question 2 way databinding in Aurelia custom elements - bind custom element to parent viewmodel
Now I need to be able to reuse the allSelectableValues from my custom element (my-custom.js) in my parent element (create.js).
I need this for a custom value converter I have on create.js which contains some Ids which I need to display names for instead, by looping through the array of elements, currently fetched and residing in my custom element.
**create.html**
<td>${d.SomeID | allSelectableValuesMapping}</td>
and
**value-converters/all-selectable-values-mapping.js**
export class AllSelectableValuesMappingValueConverter {
toView(value) {
for(let item in allSelectableValues) {
if (item.SomeID == value){
return item.Name;
}
}
}
}
In the ideal world I'd have hoped something like this would have worked:
**my-custom.js**
async attached() {
this.allSelectableValues= await await this.myService.getAllValues();
this.parent.allSelectableValues = this.allSelectableValues;
}
But my custom element have no idea of the parent which is requiring it.
Does anyone have an idea how to set the parent's allSelectableValues equal to the custom element's allSelectableValues from within the custom element? Or is there another, better way of achieving it, while still maintaining the two-way databound custom element?
Something like this ?
Please take extra note of the #customElement('CustomElement') declarator above the export class CustomElement line of code.
Custom Element View Model
import {inject} from 'aurelia-framework';
import {customElement} from 'aurelia-framework';
import {bindable} from 'aurelia-framework';
#customElement('CustomElement')
export class CustomElement {
#bindable arrItems
}
Custom Element HTML
<template>
<div repeat.for="item of arrItems">$(item.someProperty}</div>
</template>
Parent View Model
export class ParentViewModel {
parentArrItems = [];
}
Parent HTML
<template>
<require from="customelement"></require>
<CustomElement arrItems.bind="parentArrItems"></CustomElement>
</template>