I just started to learn OOP in JavaScript and right at the beginning I got some problems.
I want to use jQuery in my own Class like so:
var myclass = function() {
this.attr1 = false;
this.target1 = false;
this.func1 = function() {
this.target1.text(this.attr1);
console.log(this.attr1);
}
}
var testObj = new myclass();
$.extend(testObj, $);
testObj.attr1 = "Hello World";
testObj.target1 = $("#targetcontainer");
testObj.func1();
<div id="targetcontainer">some1 out there?</div>
But my Container did not change the text. Could you may help me?
Well you need to make sure the dom has been created before you attempt to query for elements using selectors.
var myclass = function() {
this.attr1 = false;
this.target1 = false;
this.func1 = function() {
this.target1.text(this.attr1);
console.log(this.attr1);
}
}
$(document).ready(function() {
var testObj = new myclass();
$.extend(testObj, $);
testObj.attr1 = "Hello World";
testObj.target1 = $("#targetcontainer");
testObj.func1();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="targetcontainer">some1 out there?</div>
Related
I use JSLink to color rows in a SharePoint 2013 list
ExecuteOrDelayUntilBodyLoaded(function () {
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
RegisterModuleInit(_spPageContextInfo.siteServerRelativeUrl + "/SiteAssets/jsLink.js", Highlight);
Highlight();
}
});
});
function Highlight() {
var HighlightFieldCtx = {};
HighlightFieldCtx.Templates = {};
HighlightFieldCtx.Templates.Fields = {};
HighlightFieldCtx.OnPostRender = postRenderHandler;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(HighlightFieldCtx);
}
function postRenderHandler(ctx)
{
var rows = ctx.ListData.Row;
for (var i=0;i<rows.length;i++)
{
// do stuff
row.classList.add("Color");
}
}
I need add SP.SOD.executeFunc() for activate _spPageContextInfo. But when I added SP.SOD.executeFunc(), function postRenderHandler not called in line with HighlightFieldCtx.OnPostRender = postRenderHandler.
When I dont have SP.SOD.ExecuteFunc() and static link on my JS and CSS, my code and rendering fully working. Can you please help me, how to make proper code with working _spPageContextInfo?
Try this:
<script type="text/javascript">
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () {
//alert(_spPageContextInfo.siteServerRelativeUrl);
RegisterModuleInit(_spPageContextInfo.siteServerRelativeUrl + "/SiteAssets/jsLink.js", Highlight);
Highlight();
});
function Highlight() {
var HighlightFieldCtx = {};
HighlightFieldCtx.Templates = {};
HighlightFieldCtx.Templates.Fields = {};
HighlightFieldCtx.OnPostRender = postRenderHandler;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(HighlightFieldCtx);
}
function postRenderHandler(ctx)
{
var rows = ctx.ListData.Row;
alert('postRenderHandler');
}
</script>
I have been learning about web components and I have the following code:
<input is="totally-not-checkbox">
<script>
var protoInput = Object.create(HTMLInputElement.prototype);
protoInput.createdCallback = function() {
this.style.color = "orange";
};
var nCB = document.registerElement("totally-not-checkbox", {
prototype: protoInput,
extends: 'input'
});
</script>
It is a simple implementation of "extended custom element", now I try to do the same but instead of using an INPUT I use a BUTTON:
<button is='MY-button'>hola</button>
<script>
var Proto = Object.create(HTMLButtonElement.prototype);
Proto.createdCallBack = function() {
this.style.color = "orange";
}
var tmp = document.registerElement('MY-button', {
prototype: Proto,
extends: 'button'
});
</script>
But with the BUTTON the extension is not done correctly; Consequently the BUTTON does not take the indicated properties.
what am I doing wrong?
You should check the syntax of the callback:
Proto.createdCallback
instead of:
Proto.createdCallBack
I would like to create a clean solution for handling missing image on the client
using <img src="image.gif" onerror="handleErrors()">
so far the handleErrors looks like this:
function handleErrors() {
image.onerror = "";
image.src = "/images/noimage.gif";
return true;
}
But I feel this is not scalable enough and the no image is also not accessible for screen readers.
What could be a more scalable and accessible solution for this problem?
Try using the alt text attribute for your images.
They are more accessible for screen readers.
Also you can create a module which on error hides the images and
replaces them with their alt text
Here is a module I wrote for handling such issues:
function missingImagesHandler() {
var self = this;
// get all images on the page
self.pageImages = document.querySelectorAll("img");
self.ImageErrorHandler = function (event) {
// hide them
event.target.style.display = 'none';
// replace them with alt text
self.replaceAltTextWithImage(event.target);
}
self.replaceAltTextWithImage = function (imageElement) {
var altText = imageElement.getAttribute("alt");
if (altText) {
var missingLabel = document.createElement("P");
var textnode = document.createTextNode(altText);
missingLabel.appendChild(textnode)
imageElement.parentNode.insertBefore(missingLabel, imageElement);
} else {
console.error(imageElement, "is missing alt text");
}
}
self.attachErrorHandler = function () {
self.pageImages.forEach(function (img) {
img.addEventListener("error", self.ImageErrorHandler);
});
}
self.init = function () {
// NodeList doesn't have forEach by default
NodeList.prototype.forEach = Array.prototype.forEach;
self.attachErrorHandler();
}
return {
init: self.init
}
}
var ImgHandler = new missingImagesHandler();
ImgHandler.init();
HTML:
<img id="myImg" src="image.gif">
JavaScript:
document.getElementById("myImg").onerror = handleErrors();
function handleErrors() {
document.getElementById("myImg").src = "http://blog.stackoverflow.com/wp-content/uploads/stackoverflow-logo-300.png";
return true;
}
Give an ID to image and use this for call your function:
document.getElementById("myImg").onerror = handleErrors();
Giving an ID is more suitable way.
Well, I'm using object orientation in JavaScript, but instead of using new, I just call the method from the namespace. In the moment, I have the following code:
var Component = {
Button: function(_text, use_image) {
button = $.createElement('button')
if (use_image != false)
{
button.innerHTML = _text;
}
else
{
button.innerHTML = _text
}
var text = _text
return button
}
}
When I want to return a button, I do:
x = Component.Button("Click me")
And after I can use x. But if I want to change the text of x, I must use x.textContent. I'd like to instantiate this and use a setter to apply its text, this way:
x = new Component.Button("Click me")
x.text = "Don't click me"
document.getElementsByTagName("body")[0].appendChild(x)
And if I try to apply the setter text, it becomes global, I want to have a unique for each button. Mix namespaces with get/set.
Thank you in advance
One way can be like, I am not sure if this is the best approach. Looking for more answers
var Component = {
Button: function(_text, use_image) {
var button = {
node : document.createElement('button'),
setText : function(txt){this.node.innerHTML = txt;}
};
if(_text){button.setText(_text);}
return button;
}
};
x = Component.Button("Click me");
x.setText("Don't click me");
document.getElementsByTagName("body")[0].appendChild(x.node);
y = Component.Button("Click me2");
y.setText("Don't click me2");
document.getElementsByTagName("body")[0].appendChild(y.node);
http://jsfiddle.net/2LCyn/
How about something like this:
var Component = (function($){
var buttonCount = 0;
function Button(text, use_image){
this.id = ++buttonCount;
this.text = text;
this.use_image = use_image;
this.$element = $('<button/>').text(text);
this.bindEvents();
}
Button.prototype.bindEvents = function(){
var that = this;
this.$element.on('click', function(){
console.log('hello, I\'m button ' + that.id);
});
};
Button.prototype.setText = function(text){
this.text = text;
this.$element.text(text);
};
return {
Button: Button
}
})(jQuery);
var button1 = new Component.Button('hello', false);
button1.setText('helloooo');
$('body').append(button1.$element);
var button2 = new Component.Button('world', true);
$('body').append(button2.$element);
http://jsfiddle.net/ATmAx/1/
I'm trying to convert a JavaScript function that ran off a click event to launch on page load and window resize. As you can see below, I commented out the section governing the click event and added the last line "window.onload," and manually added the class="resizerd" to the element it was working with.
The function isn't running at all. Chrome's Dev tools are showing "Uncaught TypeError: Cannot set property 'prevWidth' of undefined" Did I mess up the syntax somewhere? Any advice for how to launch this on load?
Thank you!
//var clicked = document.getElementById("buttonImportant")
var resizeeContainer = document.getElementById('video_container');
var resizee = resizeeContainer.getElementsByTagName('video')[0];
/*clicked.addEventListener('click',function(){
if( resizeeContainer.className.lastIndexOf("resizerd")>=0 ){
}
else
{
resizeeContainer.className="resizerd";
}*/
myResizerObject.prevWidth = resizee.offsetWidth;
myResizerObject.prevHeight = resizee.offsetHeight;
myResizerObject.Init();
//},false);
myResizerObject.prevWidth = resizee.offsetWidth;
myResizerObject.prevHeight = resizee.offsetHeight;
myResizerObject.Init();
var RESIZER = function(){
this.prevWidth = resizee.offsetWidth;
this.prevHeight = resizee.offsetHeight;
this.resizee = resizeeContainer.getElementsByTagName('video')[0];
this.resizeeContainer = resizee.parentNode;
this.resizeeStyle = this.resizee.style;
var ratio = this.resizee.offsetHeight/this.resizee.offsetWidth;
var that = this;
this.Init = function(){
if( that.resizeeContainer.className.lastIndexOf("resizerd")>=0 )
{
var resizeeContOffsetWidth = that.resizeeContainer.offsetWidth;
var resizeeOffsetWidth = that.resizee.offsetWidth;
var resizeeContOffsetHeight = that.resizeeContainer.offsetHeight;
var resizeeOffsetHeight = that.resizee.offsetHeight;
if(that.prevWidth!= resizeeContOffsetWidth)
{
that.prevWidth = resizeeContOffsetWidth;
var desired = resizeeContainer.offsetHeight/resizeeContainer.offsetWidth;
if(desired>ratio){
that.resizeeStyle.width=resizeeContOffsetWidth*desired+resizeeContOffsetWidth*desired+"px";
that.resizeeStyle.left = -1*(resizeeOffsetWidth-resizeeContOffsetWidth)/2+'px';
}
else{
that.resizeeStyle.cssText="width:100%;height:auto;position:fixed;";
}
}
if(that.prevHeight!=resizeeContOffsetHeight)
{
that.prevHeight = resizeeContOffsetHeight;
var desired = resizeeContOffsetHeight/resizeeContOffsetWidth;
if(desired>ratio){ console.log(ratio);
//that.resizeeStyle.top = '0px';
that.resizeeStyle.left = -1*(resizeeOffsetWidth-resizeeContOffsetWidth)/2+'px';
that.resizeeStyle.width = resizeeContOffsetHeight*desired+resizeeContOffsetHeight/desired+'px';
}
else
{
that.resizeeStyle.top = -1*(resizeeOffsetHeight-resizeeContOffsetHeight)/2+'px';
}
}
}
};
};
var myResizerObject = new RESIZER();
window.onresize = myResizerObject.Init;
window.onload = myResizerObject.Init;
Did you try to execute the function through the <body> tag?
Like:
<body onload="myfunction();">
Try calling the entire resize javascript function in the OnLoad="myfunction();" event of the Body of the page. I have done this to resize the page everytime it loads and it works just fine.
You have this line:
myResizerObject.prevWidth = resizee.offsetWidth;
That is probably giving the error. You've done nothing to declare myResizerObject so it cannot have a property prevWidth.
Somewhere down there you do
var myResizerObject = new RESIZER();
I suspect you want those lines in a more reasonable order :)
Such code should work just fine:
var myResizerObject = new RESIZER();
function UpdateResizerObject() {
var resizeeContainer = document.getElementById('video_container');
var resizee = resizeeContainer.getElementsByTagName('video')[0];
myResizerObject.prevWidth = resizee.offsetWidth;
myResizerObject.prevHeight = resizee.offsetHeight;
myResizerObject.Init();
}
window.onload = function() {
UpdateResizerObject();
};
window.onresize = function() {
UpdateResizerObject();
};
Have it after you define the RESIZER class though.
Your mistake was calling the object instance variable before creating it.
Edit: some basic debug.. add alerts to the function like this:
this.Init = function(){
alert("Init called.. container: " + that.resizeeContainer);
if (that.resizeeContainer)
alert("class: " + hat.resizeeContainer.className);
if( that.resizeeContainer.className.lastIndexOf("resizerd")>=0 )
{
...
}
}
And see what you get.