maximosis
maximosis

Reputation: 109

How to invoke a function when a class is instantiated

I have two classes, one of which is a subclass of the other. What I want to do is have one of the functions, step, invoked when the subclass is instantiated. This will cause the subclass to blink. I can see how to do it with functional instantiation but not with pseudoclassical. I've attached the jquery and javascript. Basically, when the button is clicked, I want the blinky dancer to blink, this should happen via the step function. Maybe I'm calling it incorrectly in the dancer superclass?

$(document).ready(function() {
  window.dancers = [];

  $('.addDancerButton').on('click', function(event) {

    var dancerMakerFunctionName = $(this).data('dancer-maker-function-name');
    console.log(dancerMakerFunctionName);

    var dancerMakerFunction = window[dancerMakerFunctionName];


    var dancer = new dancerMakerFunction(
      $("body").height() * Math.random(),
      $("body").width() * Math.random(),
      Math.random() * 1000
    );
    $('body').append(dancer.$node);
  });
});



var makeBlinkyDancer = function(top, left, timeBetweenSteps) {
  makeDancer.call(this, top, left, timeBetweenSteps);
};

makeBlinkyDancer.prototype = Object.create(makeDancer.prototype);
makeBlinkyDancer.prototype.constructor = makeBlinkyDancer;

var oldStep = makeBlinkyDancer.prototype.step;

makeBlinkyDancer.prototype.step = function() {
  oldStep();
  this.$node.toggle();
};

var makeDancer = function(top, left, timeBetweenSteps) {
  this.$node = $('<span class="dancer"></span>');
};
makeDancer.prototype.step = function() {
  setTimeout(step.bind(this), timeBetweenSteps);
};



makeDancer.prototype.setPosition = function (top, left) {
  var styleSettings = {
    top: top,
    left: left
  };
  this.$node.css(styleSettings);
};

// makeDancer.prototype.setPosition();

Upvotes: 0

Views: 807

Answers (1)

abgregs
abgregs

Reputation: 1380

You can call the method when the subclass is instantiated by calling init in the constructor. In the example and demo I called this method makeBlink rather than step or oldStep. Hope that makes it clear.

// the subclass BlinkyDancer
var BlinkyDancer = function (top, left, height, width, timeBetweenSteps) {
  // ... get props from parent class

  // make blink when sublcass instantiated
  this.init = this.makeBlink();
};

Full Demo/Solution

Demo: https://codesandbox.io/s/call-method-when-class-instantiated-mnesxt

HTML

<body>
  <div id="app">
    <button id="make-blink">Make Blink</button>
    <button id="stop-blink">Stop Blink</button>
  </div>
</body>

JS

import $ from "jquery";

var Dancer = function (top, left, height, width) {
  this.$node = $('<div class="dancer"></div>');
  this.top = top;
  this.left = left;
  this.height = height;
  this.width = width;
  this.bg = "blue";
};

Dancer.prototype.putDancerOnScreen = function () {
  this.$node.height(this.height).width(this.width);
  this.$node.css("background-color", "blue");
  this.$node.css("position", "absolute");
  $("body").append(this.$node);
};

Dancer.prototype.setPosition = function () {
  this.$node.css("top", this.top);
  this.$node.css("left", this.left);
};

var myDancer = new Dancer(
  Math.floor(Math.random() * 500),
  Math.floor(Math.random() * 500),
  50,
  50
);
myDancer.putDancerOnScreen();
myDancer.setPosition();

// the subclass BlinkyDancer
var BlinkyDancer = function (top, left, height, width, timeBetweenSteps) {
  Dancer.call(this, top, left, height, width); // get the props set up by Dancer
  this.timeBetweenSteps = timeBetweenSteps;
  this.blinkerId = null;

  // make blink when sublcass instantiated
  this.init = this.makeBlink();
};

// set inheritance and Dancer constructor function
BlinkyDancer.prototype = Object.create(Dancer.prototype);
BlinkyDancer.prototype.constructor = Dancer;

// add subclass methods
BlinkyDancer.prototype.makeBlink = function () {
  if (this.blinkerId !== null) {
    return;
  }
  let count = 0;
  let blinkerId = setInterval(() => {
    // do whatever thing you want to indicate blinking/dancing
    if (count % 2 === 0) {
      this.$node.css("background-color", "red");
    } else {
      this.$node.css("background-color", "blue");
    }
    count++;
  }, this.timeBetweenSteps);

  this.blinkerId = blinkerId;
  console.log("blinkder id set: ", this.blinkerId);
};

BlinkyDancer.prototype.stopBlink = function () {
  if (this.blinkerId === null) {
    // already blinking
    return;
  }
  if (this.blinkerId !== null) {
    clearInterval(this.blinkerId);
    console.log("blink id cleared: ", this.blinkerId);
    this.blinkerId = null;
  }
};

// instantiate a new subclass
let myBlinkyDancer = new BlinkyDancer(
  Math.floor(Math.random() * 500),
  Math.floor(Math.random() * 500),
  50,
  50,
  25
);

// use parent class methods to put the element on screen
myBlinkyDancer.putDancerOnScreen();
myBlinkyDancer.setPosition();

const makeBlinkButton = document.getElementById("make-blink");
const stopBlinkButton = document.getElementById("stop-blink");

makeBlinkButton.addEventListener("click", function () {
  myBlinkyDancer.makeBlink();
});

stopBlinkButton.addEventListener("click", function () {
  myBlinkyDancer.stopBlink();
});

Explanation

The Dancer class takes some props related to positioning and dimensions. It gets a blue background and has two methods for adding the element to the DOM and setting the position on screen.

BlinkyDancer is a subclass that inherits all the props of Dancer as well as two new props and two new methods.

What I want to do is have one of the functions, step, invoked when the subclass is instantiated.

When a new BlinkyDancer is instantiated, we call makeBlink right away with init so the element starts blinking.

// make blink when sublcass instantiated
this.init = this.makeBlink();

I used an alternating background color to demonstrate the blinking effect.

The makeBlink and stopBlink methods work in tandem with the new props timeBetweenSteps and blinkerId.

when the button is clicked, I want the blinky dancer to blink, this should happen via the step function.

Buttons are wired up to trigger starting and stopping the blinking effect. I've replaced step in your example with simple and declarative methods for making the blink and stopping it.

makeBlinkButton.addEventListener("click", function () {
  myBlinkyDancer.makeBlink();
});

The blinking effect uses setInterval to toggle the background color using the timeBetweenSteps prop as the interval duration. startBlink starts the interval and sets blinkerId to the corresponding interval ID. To stop the blinking effect, clearInterval is passed the blinkerId to clear it (stopping the blinking effect) before resetting it to null.

BlinkyDancer.prototype.makeBlink = function () {
  if (this.blinkerId !== null) {
    return;
  }
  let count = 0;
  let blinkerId = setInterval(() => {
    // do whatever thing you want to indicate blinking/dancing
    if (count % 2 === 0) {
      this.$node.css("background-color", "red");
    } else {
      this.$node.css("background-color", "blue");
    }
    count++;
  }, this.timeBetweenSteps);

  this.blinkerId = blinkerId;
  console.log("blinkder id set: ", this.blinkerId);
};

BlinkyDancer.prototype.stopBlink = function () {
  if (this.blinkerId === null) {
    // already blinking
    return;
  }
  if (this.blinkerId !== null) {
    clearInterval(this.blinkerId);
    console.log("blink id cleared", this.blinkerId);
    this.blinkerId = null;
  }
};

Maybe I'm calling [step] incorrectly in the dancer superclass?

It looks like you were on the right track but missing parens to call the method. In your example code, rather than:

makeBlinkyDancer.prototype.step;

You would do:

makeBlinkyDancer.prototype.step();

Upvotes: 1

Related Questions