emit event with arguments from child to parent with ember 3.6 - javascript

I would like emit one event from child to parent but with some argument.
Child component javascript
import Component from '#ember/component';
export default Component.extend({
tagName: 'li',
actions: {
favoriteWasClicked() {
const organization = this.get('organization');
// organization.id value equal to 'facebook' here in my app
// we're gonna send its id to parent component "orgs" like an argument of clicked method
this.clicked(organization);
}
}
});
Parent component .hbs template
{{child-component
clicked=(action "favoriteClicked" value="organization.id")
}}
Parent component javascript controller file
import Controller from '#ember/controller';
export default Controller.extend({
actions: {
favoriteClicked(orgId) {
console.log(orgId);
}
}
});
I'm getting undefined in console.log(orgId); Why? What am i missing
Thank you!

You simply need to change organization.id to just id. What I mean is; you need to do the following:
{{child-component
clicked=(action "favoriteClicked" value="id")
}}
You send the event from the child component with an organization; which simply contains an id; but not organization.id; so it must be just id for the value property in the action passing within parent's template.
I prepared an ember twiddle for you to illustrate the solution I proposed in action. Hope that helps.

Related

Passing Data onChange from child to parent? Angular

I need to passing data from child to parent but on change.
Child component code:
<input type="file" name="file" accept="image/*"
(change)="handleInputChange($event)">
Parent component:
<app-file-uploader></app-file-uploader> //this is child component
I need pass ($event) to parent component.
You need to use Angular's Output() directive. This is how it's done:
First: In your child component, add the following import statement:
import { Output } from '#angular/core';
Second: In the child component class: add the following property:
#Output() onChange = new EventEmitter<any>();
Now in your handleInputChange($event), you need to emit the onChange property:
handleInputChange($event){
// ... all of your logic
this.onChange.emit($event); // this will pass the $event object to the parent component.
}
Finally: In your parent component template, you can call your component like this:
<app-file-uploader (onChange)="callSomeFunction($event)"></app-file-uploader>
Note: replace callSomeFunction with whatever function you're calling.
Here's the Angular Documentation on how to use Output(). Hope this answer helps you!

Call parent methods from child components (Vue.js)

I'm doing a project and I need to call parent methods from child components. How can this be accomplished in Vue.js?
You should use this.$emit('myEvent') inside of your child component, when you want to trigger the method in the parent.
Then find your child component in the template of the parent and add an event catcher on it like this:
<template>
<your-child-component #myEvent="myMethod"/>
</template>
If you want to add parameters to your method, you can add a second parameter to your emit like this:
this.$emit("myEvent", "My parameter")
For this to work you don't have to change anything in the event "catcher", as long as the method you call has a parameter.
Maybe working example will make it more clear.
https://m-vue-leaflet.netlify.app/
code- https://github.com/manojkmishra/vue-leaflet-mapping
So here if you see there are 3 vue files in components folder.
Brew.vue is parent component to BrewList.vue child component.
Brew.vue- Parent Component
BrewList.vue - Child Component
Child component BrewList.vue is using emit to send mouse-over-brew & mouse-leave-brew values to parent Brew.vue. Also, in case you are interested Brew.vue parent is sending brew prop to BrewList.vue child.
As per docs-
https://v2.vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events
Dec, 2021 Update:
It works with $emit. The name of #callTest in parent component must be same as the name of $emit('callTest') in child component.
Parent Component:
<template>
<Child
#callTest="test" // Assign 'test' method to #callTest
/>
</template>
<script>
import Child from "../components/Child.vue";
import { defineComponent } from "vue";
export default defineComponent({
name: "Parent",
components: {
Child,
},
methods: {
test() {
alert("Test");
},
}
});
</script>
Child Component:
<template>
<button #click="$emit('callTest')">Click Me</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "Child",
});
</script>
Again, the name of #callTest in parent component must be same as the name of $emit('callTest') in child component.
If you use $emit in script section, this is needed different from template section.
Child Component:
<template>
<button #click="message">Click Me</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "Child",
methods: {
message() {
this.$emit('callTest') // 'this' is needed.
}
}
});
</script>
If test method has 2 parameters, you need to call test method with 2 arguments in child component like below.
Parent Component:
<template>
<Child
#callTest="test" // Assign 'test' method to #callTest
/>
</template>
<script>
import Child from "../components/Child.vue";
import { defineComponent } from "vue";
export default defineComponent({
name: "Parent",
omponents: {
Child,
},
methods: {
test(num1, num2) { // 'test' method has 2 parameters.
alert(num1 + num2);
},
}
});
</script>
Child Component:
<template> // Call 'test' method with 2 arguments.
<button #click="$emit('callTest', 3, 5)">Click Me</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "Child",
});
</script>
Ideally, this is the right way to do so:
https://v2.vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events
On the other hand, I believe in your scenario (which I'm trying to assume cause it's not really clear), you can use this.$parent.methodName.
Keep in mind that the second suggestion is less clean. It should be used just in case of need.
So basically, there are 2 ways to answer your question
Using $emit, with syntax is #
Passing function as props, with syntax is : The same as your example
If you based on Vue docs and a lot of other Vue tutorials, you will see that they encourage people to use $emit event rather than passing function as props (the way you are using). The docs you can read here.
https://v2.vuejs.org/v2/guide/components-custom-events.html
https://v2.vuejs.org/v2/guide/components.html#Emitting-a-Value-With-an-Event
https://code.tutsplus.com/tutorials/design-patterns-for-communication-between-vuejs-component--cms-32354
vue, emitting vs passing function as props
The reason is Vue philosophy is passing props down, emitting events up. Using $emit will help to mark the function triggered as a Vue event, and therefore you can use global event listener. This will also may help you to separate between data flow logic and event flow logic.
However, using function as props is not wrong, and in fact, it can be used to achieve the same result. In my preference, I use the 2nd way when I write a component that has a default function, and the function is only overridden when parents pass another one. This will help me avoid rewriting default functions many times.
For the rest of the other cases, I will use the 1st way $emit.
Parent
<complited v-on:passData="fromChild" />
methods: {
fromChild(data) {
if (data.methodCall) return this[data.methodCall]();
}
aFunction() {
alert('function: a');
}
bFunction() {
alert('function: b');
}
}
Child
<template>
<div>
<button #click="parentCall()">Call Parent Function
</button>
</div>
</template>
methods: {
parentCall() {
this.$emit("passData", {methodCall: 'aFunction' });
}
}
I did this with props.passed the parent method through props to the child component. and accessed from the child component.
in child component
props: ["lesson","fetchLessons"],
and accessed props like this in child component
this.fetchLessons();
parent component
<InstructorLesson v-for="(lesson,index) in getFechedLessons" :lesson="lesson" :fetchLessons = "fetchLessons" v-bind:key="index"/>

How to use multiple copies of same child tag having Event Emitter in it at the same time.

I am having a child component which emits data through event emitter.The Emitting data is bind with ngModel in parent. And the emitting method in it is called from parent component.
I have created child component because i am having two same form. So i created a single form component and used it twice and binded with their data.
//Child Component Code
import {Component, EventEmitter, Input, Output} from 'angular2/core'
#Component({
selector: 'child-component',
template: `
<input [ngModel]="formObj.title" >
`
})
export class ChildComponent {
#Input() formObject: Object;
#Output() formObjectChange= new EventEmitter();
emitChangeforParent() {
this.formObjectChange.emit(newValue);
}
}
//Parent Component
#Component({
selector: 'parent-component',
template: `
<child-component[(formObject)]="doseObject1" #firstForm></child-component>
<child-component[(formObject)]="doseObject2" #secondForm></child-component>
<button (click)="save()">Save</button>
`
})
export class ParentComponent {
doseObject1 ={title:''};
doseObject2 ={title:''};
save(){
this.firstForm.emitChangeforParent();
this.secondForm.emitChangeforParent();
console.log(this.doseObject1); //Updated data by child is available.But this works when i used single tag.
But when i use multiple child tag it does not work
}
}
Problem is that whenever I use single form tag it works fine. The update done by child is reflected here in parent.
But when i use same tag tag twice, than on calling its child emitChangeForParent() method does not work.
I think you might be a little confused about how emitChangeForParent should work. This kinda of method would usually be called by the child, and used by the parent.
so the child component would have (change)="emitChangeForParent() , then on the parent you you would have
basically this means whenever the child component calls emit, it passes the data up, and the parent component can catch it by having a callback.
However, In this case I dont think you need to do that. This is most useful for value types like numbers. If you are passing in an refence type, like your json object doseObject1 ={title:''}, the parent object should still have an up to date reference to it.
I think all you need to do to make this work is have you child component template be "" with the banana in the box double binding syntax. Then the parent will still always have an accurate value of doseObject1.title and doseObject2.title
There is no need to emit the data. The double binding syntax returns the changes done in child component to parent component.

React: pass ref through?

I'm trying to figure out how to get access to a "public" method on a React Component, that's been decorated with any number of higher-order components. Something like this:
class Toolbar extends React.Component {
openSubMenu(menuName) {
// whatever
}
render() {
// whatever
}
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
preload(), // custom higher order component which displays loading state
)(Toolbar);
If I now get a ref on the toolbar, the openSubmenu method isn't available, because it's hidden under (in this case 2) higher order components. Is there anyway to get to an arbitrary method on the underlying component?
Refs Aren't Passed Through
While the convention for higher-order components is to pass through all props to the wrapped component, it's not possible to pass through refs. That's because ref is not really a prop — like key, it's handled specially by React. If you add a ref to an element whose component is the result of an HOC, the ref refers to an instance of the outermost container component, not the wrapped component.
check https://facebook.github.io/react/docs/higher-order-components.html
Check the working demo: JSFiddle
Based on the one-way data flow nature of React, a component function is always triggered by some passed-in props value:
var Toolbar = React.createClass({
render: function() {
console.log(this.props);
return <div className={this.props.active ? "active" : ""}>Menu Item</div>;
}
});
var Parent = React.createClass({
open: function() {
this.setState({
subMenuActive: true
});
},
render: function() {
console.log(this.state);
var isActive = (this.state || {})['subMenuActive'];
return <div><Toolbar active={isActive}></Toolbar><button onClick={this.open}>Open sub menu</button></div>;
}
});
So the process should be reversed, which means: a component should be used by others, which will trigger different behaviours by specifying different props value.
If you want to trigger some specific function inside the component (instead of changing a className in the example), you need to write some code in some special functions like componentWillReceiveProps or componentDidMount. There functions will be called by React at some particular moment: https://facebook.github.io/react/docs/component-specs.html

How to get route parameter in aurelia custom component

I'm creating a custom component in aureliajs framework and injecting it a Router instance:
#inject(Router)
export class Pagination {
constructor(router) {
this.router = router;
}
}
It will be used with list view-models in order to setup some basic pagination. Therefore I need to read current page number from an active route (that would look like: orders/:pageNum. I'm not sure however how to do it? I mean - I know it should probably be placed in Pagination attached method, but how to get to this :pageNum param?
Create a bindable property in your custom element. Take the page number from the active route and bind it to the custom element. For instance:
import { bindable } from 'aurelia-framework';
#inject(Router)
export class Pagination {
#bindable page;
constructor(router) {
this.router = router;
}
}
Usage:
<pagination page.bind="page"></pagination>
To get the page number in the active route, use the activate() hook:
activate(params) {
this.page = params.pageNum;
}
You can use router.currentInstruction.params and router.currentInstruction.queryParams.
You can also observe the router to be notified when the route changes:
let sub = this.bindingEngine.propertyObserver(
this.router, 'currentInstruction').subscribe(currentInstruction => {
console.log(currentInstruction);
});

Categories

Resources