CroudTech / vue-fullcalendar

FullCalendar Wrapper for vue
MIT License
483 stars 100 forks source link

Event listener not working #12

Closed Jaquedeveloper closed 7 years ago

Jaquedeveloper commented 7 years ago

I've tried to call the event refetch-events but it is not working. The event is not being fired.

I have to call it inside of the component and outside of it. I've tried to log some info to see if the event is being fired, but it's not.

I've used

$(this.$el).fullCalendar('refetchEvents'); and $(self.$el).trigger('refetchEvents'); and $(self.$el).trigger('refetch-events', event);

but it doesn't works. I call an iframe to create the event and after it closes, the event is created and I need to refetch them.

Here's a piece of my code:

    select(start, end, jsEvent) {
        var data = start.format("YYYY-MM-DD");
        var dia = start.format("dddd");

        $.fancybox({
            type: "iframe",
            href: "http://127.0.0.1:8000/admin/agendamentos/create",
            width: "80%",
            height: "90%",
            afterLoad: function() {
                    $(".fancybox-iframe").contents().find("input[name='dia_semana']").val(dia);
                    $(".fancybox-iframe").contents().find("select[name='profissionais[]']").attr("disabled","disabled");
                    $(".fancybox-iframe").contents().find("input[name='data']").val(data);
                    $(".fancybox-iframe").contents().find("input[name='data']").attr("readonly","readonly");
            },
            afterClose: function(){
                    console.log('afterclose');
                    $(self.$el).trigger('refetch-events');
             }
        });
    },

I'll need to call this event not only inside the component, but also outside of it. Once an event is created inside my Fancybox iframe, I'll send a notification to other users and also update their views, by refetching the events. I am already sending a live notification, but I need also the event to appear on the calendar without having to refresh the page. How can I get it working?

Here's the full code:

<template>
    <div ref:"calendar" id="calendar" :event-sources="eventSources">
    </div>
</template>

<script>
    require('fullcalendar')

    export default {
        props: {
            events: {
                default() {
                    return []
                }
            },
            eventSources: {
                default() {
                    return [
                        {
                            events(start, end, timezone, callback) {
                                Vue.http.get('http://127.0.0.1:8000/getAgendamentosEventos', {timezone: timezone}).then(response => {
                                    callback(response.data.events)
                                })
                            },
                            color: '#1ABC9C',
                        },
                        {
                            events(start, end, timezone, callback) {
                                Vue.http.get('http://127.0.0.1:8000/getDatasFechadas', {timezone: timezone}).then(response => {
                                    callback(response.data.events)
                                })
                            },
                            color: '#DC0000',
                        }
                    ]
                },
            },
            editable: {
                default() {
                    return true
                },
            },
            selectable: {
                default() {
                    return true
                },
            },
            selectHelper: {
                default() {
                    return true
                },
            },
            header: {
                default() {
                    return {
                        left:   'prev,next today',
                        center: 'title',
                        right:  'month,agendaWeek,agendaDay'
                    }
                },
            },
            defaultView: {
                default() {
                    return 'month'
                },
            },
            sync: {
                default() {
                    return false
                }
            },
        },
        mounted() {
            const cal = $(this.$el),
                self = this;

            cal.fullCalendar({
                header: this.header,
                defaultView: this.defaultView,
                editable: this.editable,
                selectable: this.selectable,
                selectHelper: this.selectHelper,
                aspectRatio: 2,
                slotDuration: '00:10:00',
                timeFormat: 'HH:mm',
                events: self.events,
                eventSources: self.eventSources,
                fixedWeekCount: false,
                eventRender(event, element) {
                    if (this.sync) {
                        self.events = cal.fullCalendar('clientEvents')
                    }
                },
                eventDestroy(event) {
                    if (this.sync) {
                        self.events = cal.fullCalendar('clientEvents')
                    }
                },
                eventClick(event) {
                    $(self.$el).trigger('event-selected', event);
                    console.log('click');
                    console.log(event);
                },
                eventDrop(event) {
                    console.log('drop-event');
                    $(self.$el).trigger('event-drop', event);
                },
                eventResize(event) {
                    $(self.$el).trigger('event-resize', event)
                },
                select(start, end, jsEvent) {
                    var data = start.format("YYYY-MM-DD");
                    var dia = start.format("dddd");

                    console.log(event);

                    $.fancybox({
                            type: "iframe",
                            href: "http://127.0.0.1:8000/admin/agendamentos/create",
                            width: "80%",
                            height: "90%",
                            afterLoad: function() {
                                $(".fancybox-iframe").contents().find("input[name='dia_semana']").val(dia);
                                $(".fancybox-iframe").contents().find("select[name='profissionais[]']").attr("disabled","disabled");
                                $(".fancybox-iframe").contents().find("input[name='data']").val(data);
                                $(".fancybox-iframe").contents().find("input[name='data']").attr("readonly","readonly");
                            },
                            afterClose: function(){
                                console.log('afterclose');
                                $(self.$el).trigger('refetch-events');
                            }
                    });
                },
            });
        },
        watch: {
            events: {
                deep: true,
                handler(val) {
                    const cal = $(this.$el)
                    cal.fullCalendar('removeEvents')
                    cal.fullCalendar('addEventSource', this.events)
                    cal.fullCalendar('rerenderEvents')
                    cal.fullCalendar('refetch-events')
                    cal.fullCalendar('refetchEvents')
                },
            }
        },
        events: {
            'remove-event'(event) {
                $(this.$el).fullCalendar('removeEvents', event.id)
            },
            'rerender-events'(event) {
                $(this.$el).fullCalendar('rerenderEvents')
            },
            'refetch-events'(event) {
                console.log('refetch');
                $(this.$el).fullCalendar('refetchEvents');
            },
            'render-event'(event) {
                $(this.$el).fullCalendar('renderEvent', event)
            },
            'reload-events'() {
                $(this.$el).fullCalendar('removeEvents')
                $(this.$el).fullCalendar('addEventSource', this.events)
            },
            'rebuild-sources'() {
                $(this.$el).fullCalendar('removeEvents')
                this.eventSources.map(event => {
                    $(this.$el).fullCalendar('addEventSource', event)
                })
            },
        },
    }
</script>
BrockReece commented 7 years ago

Hello,

Maybe I have misunderstood the question but the event handlers in this component are Vue events from Vue 1.x that call the jQuery events on fullcallendar. They can be triggered from the parent component with:

this.$broadcast('event-name')

BTW, The $(this.$el) jQuery selector will only ever work inside its own component

I hope this helps? Brock

Jaquedeveloper commented 7 years ago

@BrockReece Thanks.

I'm using Vue 2.0 in my project along with Laravel. I've seen that the broadcast is deprecated in Vue 2.0.

My goal is to have live updates, so every time a new event is created, another call to the server is made (through the 'refetch-events' event) in order to get the list of events again and get it the appear in the view.

The vue-fullcalendar docs says it listens on this Event:

refetch-events() - Makes another JSON call to event sources

Which I think is the most appropriate for my case... I am already listening to event creation using laravel broadcasting system, Pusher and another Vue component. Every time a new event is created a notification is shown on the screen.

I'm pretty lost trying to make the live updates in my vue-fullcalendar component...

I've seen something about bus events, should I use event hub and $emit? eventHub.$emit(eventName)

Again, thanks for your response.

BrockReece commented 7 years ago

@Jaquedeveloper

Cool, So I have just moved to Vue 2 myself and I am still trying to figure out the best way to handle the events too.

I think I am going to build a standalone Vue2 application this morning and try out a few different things and then I will get back to you.

You definitely have the correct fullcalendar event btw, I have built something similar in Vue 1 in the past and that worked for me.

BrockReece commented 7 years ago

So I have just published a new version of the repo which I hope will address some of your issues. I am a bit pressed for time at the moment, but here is an example webpack app I built using the new version. Give me a shout though if you need anything explaining.

https://github.com/BrockReece/vue-fullcalendar-example

Jaquedeveloper commented 7 years ago

@BrockReece, Thank you very much. It will help not only me but other developers too, for sure. For now I am getting two Unexpected token { errors and when the page loads, a blank page with Cannot GET / is shown... I've been trying to figure out why. l'll try to figure it out and tell you how I go.

The errors:

 ERROR  Failed to compile with 2 errors                               9:44:23 PM

 error  in ./~/fullcalendar/dist/fullcalendar.css

Syntax Error: Unexpected token {

 @ ./~/vue-style-loader!./~/css-loader?{"minimize":false,"sourceMap":false}!./~/vue-loader/lib/style-compiler?{"id":"data-v-3d91f566","scoped":false,"hasInlineConfig":false}!./~/fullcalendar/dist/fullcalendar.css 4:14-229 13:3-17:5 14:22-237
 @ ./~/vue-full-calendar/components/FullCalendar.vue
 @ ./~/vue-full-calendar/index.js
 @ ./src/main.js
 @ multi ./build/dev-client ./src/main.js

 error  in ./src/App.vue

Syntax Error: Unexpected token {

 @ ./~/vue-style-loader!./~/css-loader?{"minimize":false,"sourceMap":false}!./~/vue-loader/lib/style-compiler?{"id":"data-v-2d4b47f2","scoped":false,"hasInlineConfig":false}!./~/vue-loader/lib/selector.js?type=styles&index=0!./src/App.vue 4:14-303 13:3-17:5 14:22-311
 @ ./src/App.vue
 @ ./src/main.js
 @ multi ./build/dev-client ./src/main.js
BrockReece commented 7 years ago

Have you installed the dependencies? Do you use yarn?

Jaquedeveloper commented 7 years ago

I've followed the instructions: npm install then npm run dev

BrockReece commented 7 years ago

Ah ok sorry, that was the boilerplate readme file. I used yarn for my package management https://yarnpkg.com/en/

Jaquedeveloper commented 7 years ago

Worked like a charm! I'll use it as a basis to implement my project live updates.

BrockReece commented 7 years ago

Awesome, do you mind if I close this issue?

Jaquedeveloper commented 7 years ago

No, I've managed to get it working by calling the trigger directly from my component. I've had also to include the resources data on computed method to get it working:

mounted() {
            const cal = $(this.$el),
                self = this;

            cal.fullCalendar({
                header: this.header,
                select(start, end, jsEvent) {
                    ...
                    var calen = this.calendar;
                    ...
                    $.fancybox({
                        type: "iframe",
                        ...
                        afterClose: function(){
                            setTimeout(function(){ calen.refetchEvents(); }, 2000);     
                        }
                    });
                }
            });
},
computed: {
            eventSources() {
                const self = this;
                return [
                    {
                        events(start, end, timezone, callback) {
                            Vue.http.get('/getAgendamentosEventos', {timezone: timezone}).then(response => {
                                    callback(response.data.events)
                                })
                        },
                        color: '#1ABC9C',
                    },
                    {
                        events(start, end, timezone, callback) {
                            Vue.http.get('/getDatasFechadas', {timezone: timezone}).then(response => {
                                callback(response.data.events)
                            })
                        },
                        color: '#DC0000',
                    }
                ];
            },
        },

here's my stackoverflow question which helped me to have the insight: http://stackoverflow.com/questions/43037140/how-to-refresh-the-vuejs-view-via-event

special thanks for @BrockReece for the support. My application is up and running now.