Laravel 9: Problem emitting event from child component to parent - laravel

In my Laravel 9 project, I have a parent component, whose template includes a child component.
template>
....
....
<div v-if=item.is_visible class="col-4">
<note-details-modal-component v-bind:is_visible=item.is_visible :note_id= item.id>
</note-details-modal-component>
</div>
On clicking a button in the parent component, I set is_visible to true that renders the child component through v-if. In the child component, when I press a button, it calls a method that emits an event to the parent.
closeNow: function() {
console.log('closeNow');
// this.$parent.$emit('close_note',false);
this.$emit('close_note',false);
} ,
In the parent component, I have a method.
close_note(value)
{
console.log('In parent');
this.is_visible = ! this.is_visible;
},
When I click the close button in the child component, it calls CloseNow() in the child component, and I see that in the console.log. However, that event does not emit to the parent. I have tried all suggestions that I could find on the web. Also, I do not see any errors in the Dev console.
Could someone please tell me what's wrong in my code that is preventing the event from emitting from the child component to parent?
Thanks in advance.

The thing is that nothing refer to the emit you made. If you have this:
closeNow: function() {
console.log('closeNow');
this.$emit('close_note',false);
}
You should mention the close_note when you call the child component. It should be something like that:
<note-details-modal-component v-bind:is_visible=item.is_visible :note_id= item.id #theEmitName="theFunctionYoucall">
</note-details-modal-component>
where theEmitName is close_note and the function you call has the same name. This medium can be usefull : https://medium.com/js-dojo/component-communication-in-vue-js-ca8b591d7efa

Related

Making focus works inside a CK Editor 5 createUIElement

So I've a custom widget which renders a custom component.
conversion.for('editingDowncast').elementToElement({
model: 'modelName',
view: (modelElement, viewWriter) => {
const modelName = modelElement.getAttribute('modelName');
const modelNameView = viewWriter.createContainerElement('span', {
class: 'modelName',
'data-modelName': modelName,
});
const reactWrapper = viewWriter.createUIElement(
'span',
{
class: 'modelName__react-wrapper',
},
function (this, domDocument) {
const domElement = this.toDomElement(domDocument);
rendermodelName(modelName, domElement);
return domElement;
},
);
viewWriter.insert(
viewWriter.createPositionAt(modelNameView, 0),
reactWrapper,
);
return toWidgetEditable(modelNameView, viewWriter);
},
});
Where rendermodelName will give back a React component with a simple input box as
return (
<div>
<input type="text" />
</div>
);
https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/react.html.
But the problem is, whenever I tried to add some content inside the input, the focus is lost from the field and automatically moved to the surrounding editor. What am I missing. Tried creating a focushandler and adding the modelNameView to it.
Should I go with the new createRawElement? My current CK5 is 20.0.0 So I don't want any breaking changes coming now.
EDIT:
I researched a little bit more. seems like createRawElement may not work here. I think this doesn't have a simple solution. I tried with allowContentOf: '$block' which also not letting me focus. But these values are explicitly for normal CK widget, not for a react component.
I had the same issue and solved it by adding this tag to the parent div that wraps my Vue component.
https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/ui/widget-internals.html#exclude-dom-events-from-default-handlers
Adding from CKE Docs:
Sometimes it can be useful to prevent processing of events by default handlers, for example using React component inside an UIElement in the widget where, by default, widget itself wants to control everything. To make it possible the only thing to do is to add a data-cke-ignore-events attribute to an element or to its ancestor and then all events triggered by any of children from that element will be ignored in default handlers.
Let’s see it in an short example:
<div data-cke-ignore-events="true">
<button>Click!</button>
</div>
In the above template events dispatched from the button, which is placed inside containing data-cke-ignore-events attribute, will be ignored by default event handlers.
I faced the similar issue.
CKEditor will takes all the events on React component which you hosted on Widget.
The work around is to stop propagation of events to CKEditor which are fired from your DOM element(domElement) where your React component hosted.
Here is the sample code:
https://github.com/ckeditor/ckeditor5-core/compare/proto/input-widget#diff-44ca1561ce575490eac0d660407d5144R239
You should stop all required events. Also you can't paste any content inside the input field of React component. That will also listened by clipboardInput event of CKEditor.

Listen to events from parent component in child and execute child’s method in vue without hub

There seems to be a lot of discussion around this topic such as Stackoverflow answer using hub, Stackoverflow answer using refs, so I really like to ask experts to provide for once a clear concise answer to this question. If the answer is also just not possible please state that!
Here is the scenario:
There are two components, a parent and a child
<Parent> // There is a button here that can be clicked to emit an event using 'this.$emit()'
<Child></Child> // The child listens and once hears the event, it does something
</Parent>
What to be achieved?
Clicking the button in the Parent emits a certain event, the child will be constantly listening and once it hears the event it executes an action, such as calling a method of its own.
What is out there about this so far?
Using a hub, in Vue Hub it is clearly stated this is for Non
Parent-Child Communication, so what is the point in using it for a
parent-child communication?
Using Refs, which is given as an end solution when it is not possible to use props and events. So why it is not possible with events at first place?
My own thought
It seems to me the firing of an event and listening to it is only possible from child to parent, basically one way communication. The parent is able to emit an event but child component(s) are not able to capture the event. Why? I tried this and didn’t work:
In the parent component I have (triggered by clicking a button in the parent component):
methods: {
generateCharts: function () {
this.$emit('generate-charts')
console.log('charts generated')
}
In the child component I have:
mounted () {
this.parent.$on('generate-charts', function () {
console.log('event captured') // Here nothing gets logged to the console
})
}
Update
Just came across this answer Vue $emit.
Apparently this is not possible at all with Vue.
At first instance it seems it is a deficiency because I have been in several situations where I needed to fire an event from parent and listen to it in the child.
I can imagine there must be a reason why this is not possible with Vue, it is probably a design consideration, Vue experts explaining why this is the case, and what is the better design approach to solve in general a scenario to pass events from parent to child, would be very appreciated.
The answer is to use props and react to changes to those props. It is a little confusing to get used to at first because it seems like a lot of code to to do something simple but as your application gets more complex, the one way data flow enforced by the use of props really helps with debugging and reasoning about what the code is trying to accomplish.
For instance, a modal. Your parent sets showChildModal = true with a button click, this value is passed to the child as a prop. The child is watching for changes to the prop, when it sees it set to true it opens the modal. Finally, when the modal is closed, the child $emit('close') which the parent is watching for, and when it sees that it sets showChildModal = false
Vue.component('child', {
template: '#child',
props: ['showModal'],
name: 'child',
watch: {
showModal: function(show) {
if (show) {
window.setTimeout(() => {
if (window.confirm("Hi, I'm the child modal")) {
this.$emit('close');
} else {
this.$emit('close');
}
}, 100)
}
}
}
})
var vm = new Vue({
el: '#el',
data() {
return {
showChildModal: false
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="el">
Parent
<p>
<button #click="showChildModal = true">Click to show child modal</button>
</p>
<hr>
<p>
<child :show-modal="showChildModal" v-on:close="showChildModal = false"> </child>
</p>
</div>
<script type="x-template" id="child">
<div>
Child
<p>
modal open? {{ showModal }}
</p>
</div>
</script>

Vue: Event Methods- Confusion

I have a parent Vue which enables or disables "edit" mode. In non-edit mode all components are read only.
I've implemented this via a data object and all works fine.
I've split out some of the components in child components.
From the parent an $emit message is sent with the new edit mode state:
methods: {
toggleMode () {
this.editMode = !this.editMode
this.$emit('edit-mode-change', this.editMode)
}
Using Vue DevTools I can see the message is emitted.
However, I can't seem to receive it in my child component!I've looked a the docs, but none of the examples match this case. This is what I have currently (in the child component):
methods: {
onEditModeChange: function (mode) {
console.log('mode is', mode)
this.editMode = mode
}
Also tried:
events: {
onEditModeChange: function (mode) {
console.log('mode is', mode)
this.editMode = mode
}
Plus I'm getting an browser console error as follows:
[Vue warn]: Invalid handler for event "edit-mode-change": got false
(found in <Dimensions> at /home/anthony/Projects/Towers-Vue/src/components/assets/Dimensions.vue)
I'm sure I'm doing something basic wrong, but the docs don't reference the events: {} block, yet I've seen it on other code. Nor does it show how to implement a listener.
Thanks for taking the time to view this post, if you can point me in the right direction, it's much appreciated.
In Vue 2, events only flow laterally or up, not down.
What you really want is to simply pass a prop into your components.
In the parent JS:
toggleMode () {
this.editMode = ! this.editMode;
}
In the parent template:
<child-component-1 :editMode="editMode"></child-component-1>
...same for others...
Then simply accept editMode as a prop in each of your child components:
{
props: ['editMode']
}
You can now use editMode within your child's template. It'll track the parent's editMode, so no need for manual events/watchers.
The way vue2 works is by having a one-direction flow of the data, from parent to child, so in your parent component you can have
<template>
<child-component :isEditing="editMode"></child-component>
</template>
<script>
export default {
methods: {
toggleMode () {
this.editMode = !this.editMode
this.$emit('edit-mode-change', this.editMode)
}
}
}
and in child component you use props to get the data
Vue.component('child-component', {
props: ['isEditing'],
template: '<span>edit mode: {{ isEditing }}</span>'
})
we have cover the edit mode for the child. now if you want to send data from child to parent, then child needs to "emit" a signal to the parent, as props are "read only"
in child component you do at any point
someMethod() {
this.$emit('editDone', dataEdited);
}
and in your parent component you "intercept" the message using on:
<template>
<child-component
:isEditing="editMode"
#editDone="someParentMethod"></child-component>
</template>
Greetings!

React Native Event Emitter between components

I have two components in react native. One class name is firstClass, and the second class is secondClass. "secondClass" is a child view of firstClass. I can submit my data to my firebase from the child view, but on successful submit, I want the view to go back to "firstClass".
I have used event emitters in the past, but those were only using navigatorIOS.
My question is, does the event emitter system listen to global events, or just within their class? And if so, how do I communicate from "secondClass" to "firstClass", that I want to show "firstClass" again.
Thanks!
You can use a callback function and call it from the second component :
in the first component:
//Constructor
....
this.state ={
renderSecondComponent:false
}
....
...Your code
{
this.renderSecondComponent()
}
renderSecondComponent(){
if(this.state.renderSecondComponent){
return(
<SecondComponent callback={()=>{this.setState({renderSecondComponent:false})}}/>
)
}
}
In the second component
....Your code
// when you should go back to the first component
if(this.props.callback){
this.props.callback()
}

In angular2, how to make child image changes when parent image changes?

For example, we have two images, one is in parent component, the other is in child component. Click child image can make the parent image changes, which is easy to implement. But how can I change child image when click parent image?
I would see several ways to do that:
Create a custom event (using #Output) in the child component and fires the event to notify the parent component. See this link for more details: `Error: Output is not defined` when passing value outside a directive to parent directive
Inject the parent component instance into the child one. From the child component, directly update the property used for the image in the parent. See this answer for more details: Angular2 Exception: No provider for Service
Use a shared service with an EventEmitter property to make communicate parent and child components. See this link for more details: Delegation: EventEmitter or Observable in Angular2
Your plunker doesn't work so it's a little hard to figure out where your specific problem is. But the general case isn't too hard.
If you want to make the parent change when the child is clicked, you just need to use an output on the child. For example - clicking the child here alternates the image in the parent (working plunk)
import {Component, Output, EventEmitter} from 'angular2/core'
#Component({
selector: "child";
template:`
<div>
<h3> Child Image: </h3>
<img src="{{uri}}" (click)="imageClicked($event)" />
</div>
`
})
export class childComponent {
#Output() wasClicked: EventEmitter<Node> = new EventEmitter();
uri: string = "https://upload.wikimedia.org/wikipedia/commons/e/e5/Элемент_И-НЕ_%28100%29.PNG"
imageClicked(e) {
console.log("child component recieved click" )
this.wasClicked.emit(e)
}
}
#Component({
selector: "parent";
template:`
<div>
<h2> Parent Image: </h2>
<img src="{{uri}}" />
</div>
<child (wasClicked)="childClicked(e)"></child>
`,
directives: [childComponent]
})
export class parentComponent {
switch: boolean = false;
uri: string = "https://upload.wikimedia.org/wikipedia/commons/1/14/Элемент_Исключающее_ИЛИ_%28100%29.png"
childClicked(e){
console.log("parent recieved click event from child")
this.switch
? this.uri = "https://upload.wikimedia.org/wikipedia/commons/1/14/Элемент_Исключающее_ИЛИ_%28100%29.png"
: this.uri = "https://upload.wikimedia.org/wikipedia/commons/7/7a/Элемент_ИЛИ-НЕ_%28100%29.PNG"
this.switch = !this.switch
}
}
how to change child image when click parent image?
In general, when a parent wants to communicate something to a child, use a child input property. If you want to execute some logic, implement ngOnChanges() to be notified when an input property changes:
ngOnChanges(changes) {
console.log(changes);
}
I assume you want to do something in PauseBtnComponent when input propertyplayBtnStatus changes:
ngOnChanges(changes) {
console.log(changes);
if(changes.playBtnStatus.currentValue) { ... }
else { ... }
}
Plunker
Another option is to use #ViewChild, #ViewChildren, or #Query in the parent component to get references to the child(ren). Then you can call public method(s) on the child.

Resources