0

I want to display some key values from objects on click. Each button has a click listener calling the prototypes method for various instances of employee.

This works ok-ish.

But i want the output method to do the following when a button is clicked: - opacity:0, then slide the height of #demo to 1px(just very small), and then when the new innerHTML value is in #demo, to animate the height back to 30px and opacity to 0. I have tried to pass the callback functions in many ways, always getting type error. The next issue is how the set the this context properly when working with addEventListener and is it somehow possible to get around assigning a different function to each eventListener?

function employee(name, jobtitle, born) {
this.name=name;
this.jobtitle=jobtitle;
this.born=born;
this.callback = function(){};
 }

employee.prototype.output = function(){
var pee = document.querySelector("p");
pee.style.opacity = 0;

pee.style.height = "30px";
pee.style.opacity = 1;
return this.name + "is a " + this.jobtitle + " born in the year" + this.born};

Link to the codepen:

http://codepen.io/damianocel/pen/MeaeGX

Javascript only please, I can get this in Jquery, but there is still some learning to do for how this happens in vanilla JS.

damiano celent
  • 721
  • 6
  • 12
  • What does not work in your code? You're not even instantiating employees or invoking their methods in the code you posted. – Bergi Jun 06 '16 at 21:49
  • Can you show us how you'd solve your problem with jQuery? I'm still not sure what the problem actually is that you are facing. In fact, pure JS listeners are not so different. – Bergi Jun 06 '16 at 21:51
  • well in jquery it could be done like $("button").click(function(){$("#demo").animate({ opacity: 0 }, 100 ) .animate({ height: "2px" }, 100 ) .animate({ opacity: 1 }, 100 ) .animate({ height: "30px" }, 100 ) – damiano celent Jun 06 '16 at 22:05
  • So actually you're asking how to do animations without jQuery? Because that has nothing to do with prototypical inheritance, callbacks or contexts. – Bergi Jun 06 '16 at 22:08
  • well in jquery it could be done like $("button").click(function(){ var htmlString = $( this ).html(); $("#demo").animate({ opacity: 0 }, 100 ) .animate({ height: "2px" }, 100 function() {$("#demo").text( htmlString )};) .animate({ opacity: 1 }, 100 ) .animate({ height: "30px" }, 100 ) }); I want the output method to do the above. – damiano celent Jun 06 '16 at 22:13
  • Nah, I am also asking on how to set the this context when an object method is called with eventListener, because this will point to the clicked button here, no? – damiano celent Jun 06 '16 at 22:15
  • In that case your question appears to be a duplicate of [How to access the correct `this` / context inside a callback?](http://stackoverflow.com/q/20279484/1048572). If you want to know both, you should ask two separate questions. – Bergi Jun 06 '16 at 22:29
  • @Bergi, yes, sorry for that, I could not find a proper answer anywhere, only separate examples, but the 2 issues are often corelated, I had a hard time figuring out how they work together. – damiano celent Jun 07 '16 at 17:55

1 Answers1

1

You already use CSS transition, so for the first question it is a matter of waiting for the transition to finish before you put the text and set the height back to 30px, otherwise you interrupt the animation immediately. For that you can listen to the transitionend event.

I would also suggest not to set the style property directly, but to use classes instead. You would also want to clip your text so it does not overflow when you are animating the height.

For the second question: you can use bind to make a function reference that already has this and possibly some arguments fixed to it.

Here is the code after having made some adaptations on those points:

function employee(name, jobtitle, born) {
    this.name=name;
    this.jobtitle=jobtitle;
    this.born=born;
    this.callback = function(){};
}

employee.prototype.output = function(target){
    var whenHidden = function () {
        target.textContent = this.name + " is a " + this.jobtitle + 
                             " born in the year " + this.born;
        target.removeEventListener('transitionend', whenHidden);
        target.classList.remove('hide');
    }.bind(this);
    target.addEventListener('transitionend', whenHidden);
    target.classList.add('hide');
};

var fred = new employee("Fred Flintstone", "Caveman", 1970);
var mike = new employee("Mike Francois", "Wrestler", 1965);
var demo = document.getElementById("demo");
var output = employee.prototype.output;

document.getElementById("a").addEventListener('click', output.bind(fred, demo));
document.getElementById("b").addEventListener('click', output.bind(mike, demo));
p { 
  border:2px black solid;
  transition:.5s;
  height:30px;
  text-overflow: clip;
  overflow: hidden;
  opacity: 1;
}
p.hide {
  height: 1px;
  opacity: 0.1;
}
<button id="a">Fred</button>
<button id="b">Mike</button>
<button id="c">Tom</button>
<p id="demo"></p>
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thank you so much for this, this cleared up much confusion that many tutorials out there didn't. Allow me some questions about this. If I need the webkit prefix for transitionend, can i just pass in another argument to the eventListener? Then, the prototype.output method argument "target", where is that defined? Is it defined in this part // output.bind(fred, demo)? The next question is, what does the this in bind(this) point to? I do understand the last 2 JS lines, the bind sets the this context to #demo. Thanks for your time. – damiano celent Jun 07 '16 at 18:36
  • The next question is, if I would like to have the names displayed in a list or input elements with checkboxes, and want the same functionality, is there a way to avoid adding a click listener to every name? – damiano celent Jun 07 '16 at 18:38
  • Yes, there is: if you wrap your list of names in a parent element (a `div` for example), you can set the click listener on that parent element. You can then check which name was clicked by checking the `event.target` property. – trincot Jun 07 '16 at 18:44
  • So, just the regular event delegation then? I'll try that. – damiano celent Jun 07 '16 at 18:52