Ivan Ivan - 4 months ago 10
Javascript Question

Creating a method similar to delay in my own class

I am trying to create a method similar to delay() from JQuery.
I am creating a method called $. Remember I am not using JQuery and don't want to for this problem.

function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
this.element = document.querySelector(element);
}

$.prototype.color = function color(color) {
this.element.style.color = color;
}


I can use this method like so:

$('#foo').color('red);


It will change the color of #foo to red

What I am trying to do is set a delay before it changes the color. One way would be to do :

$.prototype.delay(time, fn) {
setTimeout(function() {
fn();
}, time);
}


and then call it like so:

$('#foo').delay(1000, function() {
$('#foo').color('red');
});


But that's not very useful, what I would like to do instead is use it like so:

$('#foo').delay(1000).color('red);


I found this but couldn't figure it out.

Thanks in advance,
I.L

Solution thanks to @georg



// create a new instance if it doesn't already exists when $ is called
function $(element) {
if(!(this instanceof $)) {
return new $(element);
}
this.element = document.querySelector(element);
this.promise = Promise.resolve(this);
this.css = this.element.style;
}

// wrapper for the promise
$.prototype.method = function(name, fn) {
$.prototype[name] = function(...args) {
this.promise.then(self => fn.apply(self, args));
return this;
};
}

// delay method,
$.prototype.delay = function(time) {
this.promise = new Promise(
resolve => setTimeout(() => resolve(this), time));
return this;
}

// example of a method to change the color
$.prototype.method('color', function (color) {
this.css.color = color;
});

// used like so
$('#foo').delay(2000).color('green');

<div id="foo">Hi there!</div>




Answer

Here's an example with promises. Requires some more work to be practical, but should give you an idea. Basically, all methods like color should operate on "resolved this" instead of just "this":

function $(element) {
  if(!(this instanceof $)) {
    return new $(element);
  }
  this.element = document.querySelector(element);
  this.promise = Promise.resolve(this)
}

$.prototype.color = function color(color) {
  this.promise.then(function(self) {
    self.element.style.color = color;
  });
}

$.prototype.delay = function(n) {
  this.promise = new Promise(
    resolve => setTimeout(() => resolve(this), n));
  return this;
}

$('#foo').color('red');
$('#foo').delay(1000).color('blue');
<div id="foo">foo</div>

For automated promisifying you can use a wrapper like this:

$.prototype.method = function(name, fn) {
  $.prototype[name] = function(...args) {
    this.promise.then(self => fn.apply(self, args));
    return this;
  };
}

and then, for example,

$.prototype.method('color', function (color) {
  this.element.style.color = color;
});