PubSub

by onejdc

HTML

<fieldset>
  <legend>
    Input
  </legend>
  
  <button id="btn1" name="btn1">
    One Listener
  </button>
  <button id="btn2" name="btn2">
    Second Listener
  </button>
  <button id="btn3" name="btn3">
    Both Listeners
  </button>
</fieldset>

<fieldset id='subs'>
  <legend>
    Subs
  </legend>
  <div>
    <label for="ear1">First Listener:</label><input name="ear1" id="ear1"/>
  </div>
  <div>
    <label for="ear2">Second Listener:</label><input name="ear2" id="ear2"/>
  </div>
  <div>
    <label for="ear3">Third Listener:</label><input name="ear3" id="ear3"/>
  </div>
</fieldset>

CSS

button {
  padding: 15px;
  margin: 15px;
}
#subs { 
  display:flex;
  flex-direction:column;
}

JavaScript

/**
 * A basic Publisher Subscriber library
 * with topic support
 **/
class PubSub {


	constructor() {
  	this.topics = {};
  }
  
  // return the topics list as an array
	getTopics() {
  	return Object.keys(this.topics);
  }
  
  // send a msg object to all subscribers of the topic(s)
  pub(topics,msg) {
  
  	// if user gave a single string for topic, convert to array for iteration
    if (typeof topics === 'string') {
    	topics = [topics];
    }
    
    topics.forEach(function(topic) {
    	this.topics[topic].forEach(function(itemObject) {
      	itemObject.subfn(msg != undefined ? msg : {});
      }.bind(this));
    }.bind(this));

  }
  
  // caller passes in topic and callback
  sub(topic, subscriber) {
  
  	let appendObject = {id: this.getUUID(), subfn: subscriber};
  
    if (!this.topics.hasOwnProperty(topic)) {
    	this.topics[topic] = [];
    } 
  	//TODO: add error handler to ensure subscriber is a function
    
    this.topics[topic] = [...this.topics[topic], appendObject];
    return appendObject.id;
  }
  
  // simple unsub
  unsub(topic, subscriber) {
    if (typeof subscriber === 'undefined') {}
  	this.topics[topic] = this.topics[topic].filter( sub => sub !== subscriber)
  }
  
  // use the subscription ID to remove from the given topic
  unsubById(topic,id) {
  	this.topics[topic] = this.topics[topic].filter( obj => obj.id !== id);
  }
  
  /* Small helper function from https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
   */
  getUUID() {
    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
      (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
    );
  }

}




/*********** Implementation ***********/
const PS = new PubSub();

class Ex {
	constructor(div,type) {
  	this.input = div;
    this.val = 1;
    this.type = type;
  }
  update(data) {
  
  	 this.val += data.payload;
  	 this.input.value = this.val;
  	/* if (data.targets.includes(this.type)) {
  	      this.val +=...