Understanding how JavaScript Prototypes work - javascript

Am messing around with prototypes to get a better understanding of how they work. I can't work out why I can't call hideHeader, whereas I can access a variable (this.header.el)
function App() {
this.init();
this.el = document.getElementById('box');
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}

You should reorder your code so that you define hideHeader before you try to invoke it.
Like this:
function App() {
this.init();
this.el = document.getElementById('box');
}
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
JavaScript is an interpreted language, it's not compiled. It is evaluated sequentially as it is loaded into memory.

You just need to change the order of how you are doing things. For example:
function App() {
this.init();
this.el = document.getElementById('box');
}
function Header() {
this.el = document.getElementById('header');
}
Header.prototype.hideHeader = function() {
this.el.style.display = 'none';
}
App.prototype.init = function () {
document.write('hello world');
this.header = new Header();
this.header.hideHeader();
this.header.el.style.display = 'none';
};
new App();
<div id="header"></div>
<div id="box"></div>

Related

Creating a tab controller in javascript?

I'm trying to make a tab controller on a div that has divs beneath it that are for content (each sibling is a tab).
Given this html:
<div id="myTabCtl">
<div id="tab1">
<img src="https://images.unsplash.com/photo-1546238232-20216dec9f72?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1000&q=80" style="width:240px;">
</div>
<div id="tab2">
Cute puppies.
<img src="https://www.telegraph.co.uk/content/dam/news/2016/05/06/rexfeatures_4950182a_trans_NvBQzQNjv4Bqeo_i_u9APj8RuoebjoAHt0k9u7HhRJvuo-ZLenGRumA.jpg?imwidth=240" style="width:240px;">
</div>
<div id="tab3">
No puppies here.
</div>
</div>
And this javascript:
Element.prototype.tabs = function () {
var tabs = [];
this.classList.add('xTabCtl');
var tab_bar = document.createElement('ul');
tab_bar.classList.add('xTabRow');
this.insertBefore(tab_bar, this.firstChild);
this.addTab = function (div,label,title,click) {
if (typeof div == 'string')
div = document.getElementById(div);
if (!div) return false;
div.style.display = 'none';
var tab_ctl = document.createElement('li');
tab_ctl.innerHTML = label;
if (title) tab_ctl.title = title;
var cnt = tabs.length;
if (click) {
tab_ctl.onclick = function () {
this.setTab(cnt);
click();
};
} else {
tab_ctl.onclick = function () {
this.setTab(cnt);
};
}
tab_ctl.style.cursor = 'pointer';
tab_ctl.style.userSelect = 'none';
tab_ctl.classList.add('xTabItem');
tab_bar.appendChild(tab_ctl);
var tab = {};
tab.elem = tab_ctl;
tab.div = div;
tab.loaded = false;
tabs[tabs.length] = tab;
return true;
}
this.setTab = function (tab_no) {
for (var i=0; i<tabs.length; i++) {
tabs[i].elem.classList.remove('xTabItemSel');
tabs[i].div.style.display = 'none';
tabs[i].loaded = false;
}
tabs[tab_no].div.style.display = 'block';
tabs[tab_no].div.classList.add('xTabItemSel');
tabs[tab_no].loaded = true;
return;
}
};
document.getElementById('myTabCtl').tabs();
document.getElementById('myTabCtl').addTab('tab1','Cute Puppies 1','Title 1');
document.getElementById('myTabCtl').addTab('tab2','Cute Puppies 2','Title 2');
document.getElementById('myTabCtl').addTab('tab3','No Puppies','Title 3',function(){alert('hello.');});
Obviously, this uses some classes that are defined in a theme css file, but that's not at issue.
addTab works, but I cannot call setTab from the onclick of each li that is added. Why not?
Perhaps bigger, there has to be a cleaner way of doing this. I like that it adds the tabs as an li so the dopes I work with only have to add the wrapper and that content. There could be multiple tab controls on a screen. I'm not using the libraries that are available because most go way too far and I want to confine it to addTab and setTab.
This problem is with clouser, when you invoke this.setTab inside event handle, the reference of this is local so it will not get actual setTab method.
Element.prototype.tabs = function () {
var tabs = [], _this = this;
this.classList.add('xTabCtl');
var tab_bar = document.createElement('ul');
tab_bar.classList.add('xTabRow');
this.insertBefore(tab_bar, this.firstChild);
this.addTab = function (div,label,title,click) {
if (typeof div == 'string')
div = document.getElementById(div);
if (!div) return false;
div.style.display = 'none';
var tab_ctl = document.createElement('li');
tab_ctl.innerHTML = label;
if (title) tab_ctl.title = title;
var cnt = tabs.length;
if (click) {
tab_ctl.onclick = function () {
_this.setTab(cnt);
click();
};
} else {
tab_ctl.onclick = function () {
_this.setTab(cnt);
};
}
tab_ctl.style.cursor = 'pointer';
tab_ctl.style.userSelect = 'none';
tab_ctl.classList.add('xTabItem');
tab_bar.appendChild(tab_ctl);
var tab = {};
tab.elem = tab_ctl;
tab.div = div;
tab.loaded = false;
tabs[tabs.length] = tab;
return true;
}
this.setTab = function (tab_no) {
for (var i=0; i<tabs.length; i++) {
tabs[i].elem.classList.remove('xTabItemSel');
tabs[i].div.style.display = 'none';
tabs[i].loaded = false;
}
tabs[tab_no].div.style.display = 'block';
tabs[tab_no].div.classList.add('xTabItemSel');
tabs[tab_no].loaded = true;
return;
}
};
document.getElementById('myTabCtl').tabs();
document.getElementById('myTabCtl').addTab('tab1','Cute Puppies 1','Title 1');
document.getElementById('myTabCtl').addTab('tab2','Cute Puppies 2','Title 2');
document.getElementById('myTabCtl').addTab('tab3','No Puppies','Title 3',function(){alert('hello.');});

Calling a function which is inside another function

I am trying to call a function which is inside a Json from outside it. I want to trigger the "next" function on button "onClick" method. Here is my code. I tried calling it by onClick={this.next}, but it is never being called by this method.
export default class PlayerLogic extends Component{
componentDidMount() {
var self = this;
var player = videojs(this.refs.video, this.props.options).ready(function () {
self.player = this;
self.player.on('play', self.handlePlay);
});
player.markers({
onMarkerReached: function () {
player.pause();
},
next : function() {
// go to the next marker from current timestamp
console.log("reached")
var currentTime = player.currentTime();
for (var i = 0; i < markersList.length; i++) {
var markerTime = setting.markerTip.time(markersList[i]);
if (markerTime > currentTime) {
player.currentTime(markerTime);
break;
}
}
}
});
}
render() {
return (
<div>
<video {... props}>
<source src={this.props.src} type={this.props.type} id={this.props.id}/>
</video>
<button onClick={this.next}>Next</button>
</div>)
}
};
You have to refactor it with state further as below,
export default class PlayerLogic extends Component{
constructor() {
super();
this.state = {
player : {}
};
}
componentDidMount() {
var self = this;
var player = videojs(this.refs.video, this.props.options).ready(function () {
self.player = this;
self.player.on('play', self.handlePlay);
});
player.markers({
onMarkerReached: function () {
player.pause();
},
next : function() {
// go to the next marker from current timestamp
console.log("reached")
var currentTime = player.currentTime();
for (var i = 0; i < markersList.length; i++) {
var markerTime = setting.markerTip.time(markersList[i]);
if (markerTime > currentTime) {
player.currentTime(markerTime);
break;
}
}
}
});
this.setState({ player: player });
}
next() {
this.state.player.next ();
}
render() {
return (
<div>
<video {... props}>
<source src={this.props.src} type={this.props.type} id={this.props.id}/>
</video>
<button onClick={this.next.bind(this)}>Next</button>
I understand that you are using React, right! Is this .jsx or .tsx? Why you don't use arrow function. It's an ES6 feature. You can do this:
next: () => {
...
}
Mostly, all browser are supported with ES6. You can try this in your browser console:
let foo = () => 5;
console.log(foo());
Or you can compile your code back to ES5 using babel:
https://babeljs.io/docs/learn-es2015/
The problem here is when you use function, javascript will assume that this.next is your button next method, not your player next method. Arrow function () => {} will preserve this as you did:
var self = this;
var callback = function() {
self.doSomethingHere();
}
var player = video(...).ready(callback);
So you just has to:
let callback = () => {
this.doSomethingHere();
}

How do I replace all instances of a class in JS with code injection?

Let's say I want to replace all instances of options on a form (Agree/Disagree/Neutral). I can't seem to make this happen for any more than the first instance of each, rather than down the entire page.
Example
Here is where I'm at so far:
<script>
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(function() {
//Songwriting
sqsRadio = document.getElementsByClassName("option")[0].innerHTML;
myRadio = sqsRadio.replace("Strongly Disagree", "Fortement Désaccord");
document.getElementsByClassName("option")[0].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[1].innerHTML;
myRadio = sqsRadio.replace("Disagree", "Désaccord");
document.getElementsByClassName("option")[1].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[2].innerHTML;
myRadio = sqsRadio.replace("Neutral", "Neutre");
document.getElementsByClassName("option")[2].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[3].innerHTML;
myRadio = sqsRadio.replace("Agree", "d'Accord");
document.getElementsByClassName("option")[3].innerHTML = myRadio;
sqsRadio = document.getElementsByClassName("option")[4].innerHTML;
myRadio = sqsRadio.replace("Strongly Agree", "Fortement d'Accord");
document.getElementsByClassName("option")[4].innerHTML = myRadio;
});
</script>

reaching the btn event outside the revealing patterned applied class

I have an revealing patterned applied class.How can I reach btnMenu event outside of the model
thanks.
MyModel= (function () {
var btnClickEvents = function () {
var btnMenu = $('.btnMenu').on('click', function () {
var date= $(this).attr("data-rezerve-date");
var statu= $(this).attr("data-rezerve-statu");
alert("click"+date+'---'+statu);
});
};
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: btnClickEvents.btnMenu//how can I reach this function outside of model
};
})();
update
I change my code as u show.and add one return function
MyModel = (function () {
var dt = "";
var statu = "";
var rvalue = {};
var btnClickEvents = function () {
$('.btnMenu').on('click', onBtnMenuClick);
};
function onBtnMenuClick(e) {
dt = $(this).attr("data-rezerve-date");
statu = $(this).attr("data-rezerve-statu");
rvalue.date = dt;
rvalue.statu = statu;
console.log(dt);
}
var getRezervationDateAndStatus = function () {
return rvalue;
};
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: getRezervationDateAndStatus
};
})();
and after include my module to my web page calling is like this,
MyModel.asignValues(rezervasyonTable,data);
MyModel.initialize();
var result = MyModel.getRezervationDateAndStatus();
console.log(result.date);
bu console log empty.
As you say it is a " revealing" pattern. You could see what you expose. To be able to use this function outside of the module change your code like this:
MyModel = (function () {
var btnClickEvents = function () {
$('.btnMenu').on('click', onBtnMenuClick);
};
function onBtnMenuClick(e) {
var date = $(this).attr("data-rezerve-date");
var statu = $(this).attr("data-rezerve-statu");
alert("click" + date + '---' + statu);
}
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: onBtnMenuClick
};
})();

javascript: How to reference a class from event

I have a class like this
var grid = function () {
this.cell = null;
this.loadImage = function () {
var image = new Image();
var object = this;
image.src = "blah";
$(image).load(function () {
object.cell = this;
});
}
this.showImage = function () {
alert(object.cell); // This should print [object Object] ... but it print null;
}
}
The showImage function is called after the image called loaded from loadImage function.
Does anyone know why object.cell is null... I have reference to this object in loadImage.
object is undefined in showImage.
This is what I think you should be doing:
var grid = function () {
this.cell = null;
this.loadImage = function () {
var image = new Image();
image.addEventListener("load", (function (obj) {
return function () {
obj.cell = this;
};
})(this));
image.src = "http://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg";
}
this.showImage = function () {
alert(this.cell);
}
}

Categories