I'm trying to make a function that works like this:
JavaScript:
let elm = document.querySelector('section')
elm.gridify();
assuming the function gridify adds display: grid; to the element.
My question is: is that possible and, if so, how?
I tried this, and it's actually working:
function gridify() {
this.gridify = function(element) {
let myElement = document.querySelector(element)
myElement.setAttribute('style', 'display: grid;')
console.log(myElement);
}
}
var test = new gridify();
test.gridify('section');
Now, what I want is to make something like what I wrote above.
First of all you have to know that edit prototype is something you should never use, but this is the only way to add a custom method to HTMLElement objects (in your case) :
HTMLElement.prototype.gridify = function() { this.style.display = "grid" };
let div = document.querySelector('#myDiv');
div.gridify();
console.log(div.style.display);
// Output
// grid
As suggested in the comments use a function gridify which takes your HTMLElementas parameter is a better practice ;)
function gridify(element) {
element.style.display = "grid";
}
gridify(div);
console.log(div.style.display);
// Output
// grid
Related
I am very new to javascript.
Here I am failing to run an object method on a DOM element that I selected through another property of the same object. I suspect there is something wrong with my thinking!
Thanks in advance for any piece of help.
var Arrow = function() {
this.current = $('.arrow');
this.previous = null;
this.bend = function() {
// do bend
};
};
var arrow = new Arrow();
arrow.current.bend();
bend() is a method of Arrow, not current. Use arrow.bend() and it will also have access to current using this.current.
arrow.current.bend is not defined.
You have defined:
this.current as the Array of DOM elements.
this.bend as method with a function.
Hence, you can call:
arrow.current >> returns Array of DOMs
arrow.bend() >> executes function bend.
arrow.current.bend() does not exist.
Also, note that arrow.current is an array. You'd first need to get each of the elements:
for (element of arrow.current) { element.bend(); }
However, as said before, element does not have a bend element by default and you have not appended at any point. Only arrow has a bend property.
I hope this guides you on why this does not work.
However, if you want to open a question on what you are trying to achieve, maybe we can help to get it fixed.
You need to call bend() on arrow object. In bend() function, you do what you need to do.
var Arrow = function() {
this.current = $('.arrow');
this.previous = null;
this.bend = function() {
// do bend
current.style = 'bent';
};
};
var arrow = new Arrow();
arrow.bend();
So two things.
You called the right method on the wrong object
arrow.bend(); // not arrow.current.bend()
The second possible problem is with this.current = $('.arrow');. To get the an element from the DOM, you should make sure it's totally loaded. I'd suggest the following
var Arrow = function($arrow) {
this.current = $arrow;
this.previous = null;
};
// To avoid creating the `bend` in every instance of Arrow
Arrow.prototype.bend = function() {
console.log(this.current.attr('id'));
};
$(function () {
// Now it's certain that the DOM is completely loaded
var arrow = new Arrow($('.arrow').first());
arrow.bend();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="arrow" id="toto">arrow<div>
I am very new to programming and I am wondering if anyone can help me with this.
I am trying to make a pop up page.
I set variables for each click area which I set each area with div and placed with css.
Also for each pop up image which I put div id on each image on html and set display = "none" on css.
I want to make a function that shows one image on touchend and hide other images at the same time.
Could you help me with my code?
var pop = new Array("pop1","pop2","pop3","pop4","pop5","pop6");
var clickArea = new Array("click1","click2","click3","click4","click5","click6");
function diplay(click,show,hide){
click.addEventListner("touchend",function(){
show.style.display = "block";
hide.style.display = "none";
});
};
display("click[0]","pop[0]","pop[1,2,3,4,5]");
There are a few different issues with your code.
You used strings instead of the actual code structure references while calling display. I see that you mean for these to reference the element ids, but you must first get the element with document.getElementById(...) or jQuery's $("#...").
In the pop and clickArea arrays, you used strings, which do not have the .style object. You need to reference the elements themselves.
Your code structure is not designed to handle arrays.
You need to define the addEventListener before you need the function handler to be called. You do not want this every time.
The click argument in the display function is redundant, as it is never called.
You are using jQuery. You should have stated this! (but you're forgiven) :)
You can't reach into arrays with the syntax arrayName[#,#,#].
You misspelled "display". Whoops!
The arrays are redundant, since the code needed to be restructured.
First, in order to address Point #4, we need this code to run when the DOM has finished loading:
var clickArea = new Array("click1","click2","click3","click4","click5","click6");
clickArea.each(function(id){
$("#"+id)[0].addEventListener("touchend", display);
});
Next, we need to fix the issues with your code. They're explained above.
var pop = new Array("pop1","pop2","pop3","pop4","pop5","pop6");
function display(event){
var indx = Number(event.target.id.split(/\D/i).join(""));
$("#pop"+indx)[0].style.display = "block";
pop.each(function(ide) {
if (ide.split(/\D/i).join("") != indx-1) {
$("#"+ide)[0].style.display = "none";
}
});
};
Otherwise, great job! All of us started out like this, and believe in you! Keep it up!
P.S. You can set arrays like this [ ? , ? , ? , ? ] instead of this new Array( ? , ? , ? , ? ).
Here is an example using for loops instead of methods of Arrays etc
Start off by defining everything you can
var popup_id = ["pop1", "pop2", "pop3", "pop4", "pop5", "pop6"],
popup_elm = [], // for referencing the elements later
area_id = ["click1", "click2", "click3", "click4", "click5", "click6"],
area_elm = [], // for referencing the elements later
i; // for the for -- don't forget to var everything you use
// a function to hide all popups
function hideAll() {
var i; // it's own var means it doesn't change anything outside the function
for (i = 0; i < popup_elm.length; ++i) {
popup_elm.style.display = 'none';
}
}
// a function to attach listeners
function listenTouch(area, popup) {
area.addEventListener('touchend', function () {
hideAll();
popup.style.display = 'block';
});
// we did this in it's own function to give us a "closure"
}
Finally we are ready do begin linking it all to the DOM, I'm assuming the following code is executed after the elements exist in the browser
// setup - get Elements from ids, attach listeners
for (i = 0; i < popup_id.length; ++i) {
popup_elm[i] = document.getElementById(popup_id[i]);
area_elm[i] = document.getElementById(area_id[i]);
listenTouch(area_elm[i], popup_elm[i]);
}
You cannot treat strings as html elements.
Assuming there are elements with click area ids in the page, you may do something like (once the document is ready).
var popEls = pop.map(function (id) { return document.getElementById(id) });
clickArea.forEach(function (id) {
var clickAreaEl = document.getElementById(id);
clickAreaEl.addEventListener('click', onClickAreaClick);
});
function onClickAreaClick() {
var clickAreaNum = +this.id.match(/\d+$/)[0],
popIndex = clickAreaNum - 1;
popEls.forEach(function (popEl) {
popEl.style.display = 'none';
});
popEls[popIndex].style.display = 'block';
}
I want to create a jquery slider using oop. This is the structure of my code :
var photoGallery = new Slider();
function Slider(){ this.init(); }
Slider.prototype = {
el : {
nav : $('.slideshowNav', this.main),
navItems : $('.items', this.nav),
main : $('.slideshow')
}
,init: function(){
// some code here
}//init
// rest of functions here
}
My problem is that i have two <div class="slideshow"> in same page and my code is wrong according to this situation.
I know that i can pass a parameter to init() and all my problems will fly away, but i use the this.el elements also in other functions so this is not a solution.
I want to know how i can add another element to this.el coming from Slider() parameter (I know, there is no parameter now)
Or, does somebody has an idea how i can make the structure which looks like
$('.slideshow').each(...)
?
I need my code working with multiple elements on a single page
Here is how many jquery plugins start:
$.fn.myplugin = function(opts) {
// Let each closure has its own options
var myplugin = new Myplugin(opts);
return this.each(myplugin);
};
function Myplugin(opts) {}
This way, people can call your code like this:
$('.slideshow').myplugin();
And each element will be handled separately. this.el will be able to be called easily in each of your instance with no issue.
You can try something like this (untested):
var galleries = [];
$('.slideshow').each(function(index, elem) {
galleries.push(new Slider(elem));
});
And then change your Slider implementation to something like this:
function Slider(elem) {
this.elem = elem;
this.init();
}
Slider.prototype = {
el : {
nav : $('.slideshowNav', this.main),
navItems : $('.items', this.nav),
main : $('.slideshow')
}
,init: function() {
// some code here
}//init
// rest of functions here
}
The new thing with this approach is, that you have a this.elem inside your Slider instance which you can refer to. You will have to adapt some of your code to refer to this.elem inside your Slider prototype to work, but this should get you started.
I need some help please with a javascript object. it goes like this:
I call this function addFilter(element) with a html DOM element.
The function looks like this:
function MyList() {
this.arr = new Array();
this.index = 0;
}
MyList.prototype.add = function(filter) {
this.arr[this.index++] = filter;
//alert(this.arr[0] + ' mylist arr');
}
function Filter(element) {
this.setElement(element);
}
Filter.prototype.setElement = function (element) {
this.element = element;
this.kinorid = $(element).attr('id');
}
function addFilter(element) {
filters.Add(new Filter(element));
}
var filters = new MyList();
Now with in another function that in my case the function creates the jquery UI Slider, and every time the slider changes i need to get the parent element of that element that was sent to addFilter like i said in the beginning. so then i try doing
var value = filters.arr[0];
but like i said it id undefined.
Can any one please help me by reviewing the code, and tell me whats wrong.
Thank you very much.
You still haven't said where or how you're using filters.arr[0], without which it's very difficult to help you.
Assuming your code using it looks something like this:
AddFilter($("#theElement"));
display(typeof filters.arr[0]);
filters.arr[0].element.css("color", "blue");
It should be working; live example.
My only thought is if AddFilter and filters are not defined within the same scope. You're using filters within AddFilter, so AddFilter must be defined in the same scope as filters (or in a sub-scope). So this would be fine:
var filters;
function AddFilter() { ... }
And this
function AddFilter() { ... }
var filters;
And this
var filters;
$(function() {
function AddFilter() { ... }
});
But not
function AddFilter() { ... }
$(function() {
var filters;
// ...
});
...because in that last case, AddFilter is defined outside the scope in which filters is defined.
Your code is very convoluted, I don't understand it at all. Anyway, you are looking for (I think):
var value = filters.arr[0].element;
since you assign the element reference to arr[this.index].
Incidentally, if you are passing an element, then:
$(this).attr('id');
is an awfully slow way to do:
this.id;
Edit
The code I used (where there was a div with id 'd0' in the DOM):
var filters = new MyList();
AddFilter(document.getElementById('d0'));
alert(filters.arr[0].element);
I edited the question so it would make more sense.
I have a function that needs a couple arguments - let's call it fc(). I am passing that function as an argument through other functions (lets call them fa() and fb()). Each of the functions that fc() passes through add an argument to fc(). How do I pass fc() to each function without having to pass fc()'s arguments separately? Below is how I want it to work.
function fa(fc){
fc.myvar=something
fb(fc)
}
function fb(fc){
fc.myothervar=something
fc()
}
function fc(){
doessomething with myvar and myothervar
}
Below is how I do it now. As I add arguments, it's getting confusing because I have to add them to preceding function(s) as well. fb() and fc() get used elsewhere and I am loosing some flexibility.
function fa(fc){
myvar=something
fb(fc,myvar)
}
function fb(fc,myvar){
myothervar=something
fc(myvar,myothervar)
}
function fc(myvar,myothervar){
doessomething with myvar and myothervar
}
Thanks for your help
Edit 3 - The code
I updated my code using JimmyP's solution. I'd be interested in Jason Bunting's non-hack solution. Remember that each of these functions are also called from other functions and events.
From the HTML page
<input type="text" class="right" dynamicSelect="../selectLists/otherchargetype.aspx,null,calcSalesTax"/>
Set event handlers when section is loaded
function setDynamicSelectElements(oSet) {
/**************************************************************************************
* Sets the event handlers for inputs with dynamic selects
**************************************************************************************/
if (oSet.dynamicSelect) {
var ySelectArgs = oSet.dynamicSelect.split(',');
with (oSet) {
onkeyup = function() { findListItem(this); };
onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }
}
}
}
onclick event builds list
function selectList(sListName, sQuery, fnFollowing) {
/**************************************************************************************
* Build a dynamic select list and set each of the events for the table elements
**************************************************************************************/
if (fnFollowing) {
fnFollowing = eval(fnFollowing)//sent text function name, eval to a function
configureSelectList.clickEvent = fnFollowing
}
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList); //create the div in the right place
var oSelected = event.srcElement;
if (oSelected.value) findListItem(oSelected)//highlight the selected item
}
Create the list
function setDiv(sPageName, sQuery, sClassName, fnBeforeAppend) {
/**************************************************************************************
* Creates a div and places a page in it.
**************************************************************************************/
var oSelected = event.srcElement;
var sCursor = oSelected.style.cursor; //remember this for later
var coords = getElementCoords(oSelected);
var iBorder = makeNumeric(getStyle(oSelected, 'border-width'))
var oParent = oSelected.parentNode
if (!oParent.id) oParent.id = sAutoGenIdPrefix + randomNumber()//create an ID
var oDiv = document.getElementById(oParent.id + sWindowIdSuffix)//see if the div already exists
if (!oDiv) {//if not create it and set an id we can use to find it later
oDiv = document.createElement('DIV')
oDiv.id = oParent.id + sWindowIdSuffix//give the child an id so we can reference it later
oSelected.style.cursor = 'wait'//until the thing is loaded
oDiv.className = sClassName
oDiv.style.pixelLeft = coords.x + (iBorder * 2)
oDiv.style.pixelTop = (coords.y + coords.h + (iBorder * 2))
XmlHttpPage(sPageName, oDiv, sQuery)
if (fnBeforeAppend) {
fnBeforeAppend(oDiv)
}
oParent.appendChild(oDiv)
oSelected.style.cursor = ''//until the thing is loaded//once it's loaded, set the cursor back
oDiv.style.cursor = ''
}
return oDiv;
}
Position and size the list
function configureSelectList(oDiv, fnOnClick) {
/**************************************************************************************
* Build a dynamic select list and set each of the events for the table elements
* Created in one place and moved to another so that sizing based on the cell width can
* occur without being affected by stylesheet cascades
**************************************************************************************/
if(!fnOnClick) fnOnClick=configureSelectList.clickEvent
if (!oDiv) oDiv = configureSelectList.Container;
var oTable = getDecendant('TABLE', oDiv)
document.getElementsByTagName('TABLE')[0].rows[0].cells[0].appendChild(oDiv)//append to the doc so we are style free, then move it later
if (oTable) {
for (iRow = 0; iRow < oTable.rows.length; iRow++) {
var oRow = oTable.rows[iRow]
oRow.onmouseover = function() { highlightSelection(this) };
oRow.onmouseout = function() { highlightSelection(this) };
oRow.style.cursor = 'hand';
oRow.onclick = function() { closeSelectList(0); fnOnClick ? fnOnClick() : null };
oRow.cells[0].style.whiteSpace = 'nowrap'
}
} else {
//show some kind of error
}
oDiv.style.width = (oTable.offsetWidth + 20) + "px"; //no horiz scroll bars please
oTable.mouseout = function() { closeSelectList(500) };
if (oDiv.firstChild.offsetHeight < oDiv.offsetHeight) oDiv.style.height = oDiv.firstChild.offsetHeight//make sure the list is not too big for a few of items
}
Okay, so - where to start? :) Here is the partial function to begin with, you will need this (now and in the future, if you spend a lot of time hacking JavaScript):
function partial(func /*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(this, allArguments);
};
}
I see a lot of things about your code that make me cringe, but since I don't have time to really critique it, and you didn't ask for it, I will suggest the following if you want to rid yourself of the hack you are currently using, and a few other things:
The setDynamicSelectElements() function
In this function, you can change this line:
onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }
To this:
onclick = function() { selectList.apply(null, ySelectArgs); }
The selectList() function
In this function, you can get rid of this code where you are using eval - don't ever use eval unless you have a good reason to do so, it is very risky (go read up on it):
if (fnFollowing) {
fnFollowing = eval(fnFollowing)
configureSelectList.clickEvent = fnFollowing
}
And use this instead:
if(fnFollowing) {
fnFollowing = window[fnFollowing]; //this will find the function in the global scope
}
Then, change this line:
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList);
To this:
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', partial(configureSelectListAlternate, fnFollowing));
Now, in that code I provided, I have "configureSelectListAlternate" - that is a function that is the same as "configureSelectList" but has the parameters in the reverse order - if you can reverse the order of the parameters to "configureSelectList" instead, do that, otherwise here is my version:
function configureSelectListAlternate(fnOnClick, oDiv) {
configureSelectList(oDiv, fnOnClick);
}
The configureSelectList() function
In this function, you can eliminate this line:
if(!fnOnClick) fnOnClick=configureSelectList.clickEvent
That isn't needed any longer. Now, I see something I don't understand:
if (!oDiv) oDiv = configureSelectList.Container;
I didn't see you hook that Container property on in any of the other code. Unless you need this line, you should be able to get rid of it.
The setDiv() function can stay the same.
Not too exciting, but you get the idea - your code really could use some cleanup - are you avoiding the use of a library like jQuery or MochiKit for a good reason? It would make your life a lot easier...
A function's properties are not available as variables in the local scope. You must access them as properties. So, within 'fc' you could access 'myvar' in one of two ways:
// #1
arguments.callee.myvar;
// #2
fc.myvar;
Either's fine...
Try inheritance - by passing your whatever object as an argument, you gain access to whatever variables inside, like:
function Obj (iString) { // Base object
this.string = iString;
}
var myObj = new Obj ("text");
function InheritedObj (objInstance) { // Object with Obj vars
this.subObj = objInstance;
}
var myInheritedObj = new InheritedObj (myObj);
var myVar = myInheritedObj.subObj.string;
document.write (myVar);
subObj will take the form of myObj, so you can access the variables inside.
Maybe you are looking for Partial Function Application, or possibly currying?
Here is a quote from a blog post on the difference:
Where partial application takes a function and from it builds a function which takes fewer arguments, currying builds functions which take multiple arguments by composition of functions which each take a single argument.
If possible, it would help us help you if you could simplify your example and/or provide actual JS code instead of pseudocode.