GithubHelp home page GithubHelp logo

naver / egjs-component Goto Github PK

View Code? Open in Web Editor NEW
38.0 12.0 9.0 1.28 MB

A class used to manage events in a component like DOM

Home Page: https://naver.github.io/egjs-component

JavaScript 28.82% TypeScript 71.18%
component javascript eventemitter egjs typescript

egjs-component's People

Contributors

daybrush avatar haeguri avatar happyhj avatar jaeyeophan avatar kishu avatar malangfox avatar mixed avatar sculove avatar uyeong avatar woodneck avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

egjs-component's Issues

Reusing trigger customEvent object

@vreality64 commented on Mon Feb 20 2017

I'll mention 3 things.

  1. Situation I been through.
  2. The thing what I expected.
  3. Solution.

Situation I been through

I have one controller and two modules. everything is class inherited from eg.Component.

// Controller, Module A, Module B
var instance = new eg.Class.extend(eg.Component, {
  // ...
});

I tried handle custom event state between modules and controller using customEvent.stop() function. But stop was not worked.

Trigger Docs: If the stop() method is called by a custom event handler, it will return false and prevent the event from occurring.

Here are code.

// Controller has Module A. Module A has Module B.
// every callback function is wrapped `$.proxy` with `this` context.
// this.module.on('eventName', $.proxy(callback, this));

// In Controller
moduleA.on('beforeSelect', function (event) {
  event.stop();
});

// In Module A
moduleB.on('beforeSelect', function (event) {
  this.trigger('beforeSelect', event);	// reuse event object
});

// In Module B
this.on('click', function (event) {
  if (this.trigger('beforeSelect')) {
    this.select('data');
  }
})

The thing what I expected

Code describes that if controller calls event.stop() then doesn't execute moduleB.select(). because stop() makes trigger return false.

I think reusing custom event is common case. normally custom event has data, so it was broadcasted to system.

But when it reused, isCanceled variable was overridden.

trigger: function(eventName, customEvent) {
  // event(data) Object are alive.
  customEvent = customEvent || {};
  
  // ...
  // isCanceled variable is overridden.
  var isCanceled = false;
  
  // ...
  return !isCanceled;
},

If intended, it is notable.

Solution

I changed middle module. not re-used event object

// [Before] In Module A
moduleB.on('beforeSelect', function (event) {
  this.trigger('beforeSelect', event);	// reuse event object
}
           
// [Changed] In Module A
moduleB.on('beforeSelect', function (event) {
  var stop = !this.trigger("beforeSelect");	// not re-used event object
  if (stop) {
    event.stop();
  }
}

I made JS fiddle example. you can reproduce my situation.

Question

I can't sure what is right, so just want to know decision history. what philosophy / thoughts leads this conclusion?


@mixed commented on Mon Feb 20 2017

@vreality64
Thank you for your report. I am going to anwser it soon. ๐Ÿ˜„


@mixed commented on Tue Feb 21 2017

I think that This case is very important issue. Sometimes Component has not to fire event. So if trigger add option like boolean for event fire condition. I think differently It is duplicate feature(stop method). So. It need more idea.

Impl to currentTarget attribute of event.

When Component triggered event, It has not found component instance in event listener.
So, Below case is inconvenience.

to-be

class Test {
	constructor(){
		this.bind();
	}
	bind(){
		const scroll = new ScrollComponent();
		scroll.on("change",this.change.bind(this));
	}
	change(e){
		// I can not found scroll instance.
	}
}

as-is

class Test {
	constructor(){
		this.bind();
	}
	bind(){
		const scroll = new ScrollComponent();
		scroll.on("change",this.change.bind(this));
	}
	change({currentTarget}){
		currentTarget; // It is scroll instance.
	}
}

Why we decided to use currentTarget

Almost Component design is affected by DOM interface. ref So. We decided to use currentTarget of DOM interface.

Returns the object whose event listener's callback is currently being invoked.

subscribe/unsubscribe method

Description

Sometimes I have to listen all event in component.

Steps to check or reproduce

class Test extends Component{
	foo(){
		this.trigger("foo",1);
	}
	bar(){
		this.trigger("bar",2);
	}
}

const test = new Test();

test.subscribe( data => {
	console.log(data);
	// {"name":"foo","data":1}
	// {"name":"bar","data":2}
});

test.foo();
test.bar();

More flexible event structures

Description

As-is:

  • Always have to use objects for event definitions

To-be:

  • Can use any types for the event definitions

Supporting esModule

Description

In the @egjs/flicking module, this @egjs/component is imported as follows for the type definition.

import * as Component from "@egjs/component";

Currently, we use esModuleInterop ts-compiler option in TypeScript 2.7.x version. So, the current version of typscript and import method are not appropriate.

How about supporting esModule like @egjs/axes?

Event Propagation

there are suggestion that is event propagation.
It is not absolutely necessary, but I think it would be good to apply.

First, let me share my experience.
the experience was limited to UI development.

i think the UI has a hierarchical structure in general, whether it is physical or conceptual.
so when i applied this component to UI, events also had to be designed to follow the hierarchy.

when, i designed to

SearchPage (independent component)
   ใ„ด SearchInput
   ใ„ด Filter
   ใ„ด Category

the event structure was as follow,

SearchPage (independent) - onSubmit, onClear, onFilter, onSort,...
   ใ„ด SearchInput - onSubmit, onClear
   ใ„ด Filter - onFilter
   ใ„ด Sort - onSort

and implemented this as below.

class SearchPage extends eg.Component {
    constructor() {
        super();
        this.context = {};
        this.searchInput = new SearchInput(); // child component
        this.filter = new Filter();  // child component
        // intercepts event
        this.searchInput.on('submit', (event) => {
            // bubbling
            event.pageContext = context;
            this.trigger(event.eventType, event)
        });
    }
}

const searchPage = new SearchPage();

searchPage.on('submit', (event) => {
    // todo - external module
})

but I thought it would be better if the component itself provided it systematically.
because the deeper the component, the more it will equal callback hell.

thanks for reading.

Change return type in `component.d.ts`

Description

In 2.1.0 version

declare class Component {
  // ...
  on(eventName: string, handlerToAttach: (event: { [key: string]: any }) => any): Component;
  // ...
}

I think this part should be changed as follows, I will ask you to review that part.

declare class Component {
  // ...
  on(eventName: string, handlerToAttach: (event: { [key: string]: any }) => any): this;
  // ...
}

=> : Componentis to be : this

In 2.1.0-snapshot, already has this part applied.
By the way, should not namespace part remain the same?

AS-IS

declare namespace Component {
  // ...
  function on(eventName: string, handlerToAttach: (event: { [key: string]: any }) => any): this;
  // ...
}

TO-BE

declare namespace Component {
  // ...
  function on(eventName: string, handlerToAttach: (event: { [key: string]: any }) => any): Component;
  // ...
}

I will request a review of that part. Thanks.

eventType is overwritten by event props

Description

If eventType is given inside event props, it will overwrite actual event name

Steps to check or reproduce

const evt = new ComponentEvent("correct_name", {
  eventType: "wrong_name"
});

evt.eventType // "wrong_name"

Manage Event

When I use many Components I tired to manage events.

Static method getInstace & destroy

class A extends Component{
}

class B extends Component{
}

new A();
new B();

Component.getInstanceAll();
// [instanceA, instanceB]
class A extends Component{
}

class B extends Component{
}

const a = new A();
new B();

Component.getInstanceAll();
// [instanceA, instanceB]

a.destory();

Component.getInstanceAll();
// [instanceB]

deprecated option, add prop.

[WIP]

I think that Currently option method is unnecessary feature. Because Almost Component update attribute directly option object.

Sometimes Component have to know changing value of options. I suggest event and method.

class SomeThing extends Component{
	constructor(){
		// setup prop
		this.prop({
			witdh : 100,
			height : 200
		});
	}
}

const someThing = new SomeThing();
someThing.on("propChange", (data) => {
	console.log(data);
	/*
	{
		width : {
			prevValue : 100,
			newValue : 200
		}
	}
	*/
});
someThing.prop("width",200);

This idea affected by DOM.

Modifying common js behavior in node environment

Description

Before

import Component from "./Component";
import ComponentEvent from "./ComponentEvent";

(Component as any).ComponentEvent = ComponentEvent;

export default Component;

After

import Component, * as modules from './index';

for (const name in modules) {
  (Component as any)[name] = (modules as any)[name];
}

declare const module: any;
module.exports = Component;
export default Component;
export * from './index';

Steps to check or reproduce

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.