I am receiving this error,
Practice.html:formatted:20 Uncaught TypeError: queueArray.push is not a function
at Queue.add (Practice.html:formatted:20)
at Practice.html:formatted:30
but push isn't supposed to be a function. It is supposed to be a method executed on an array. So what could this mean??
var tickerArray = ['BP', 'AMZN', 'EARK'];
//also tried putting queueArray here because that would make it global, so i guess it isnt a scope issue?
function Queue() {
this.top = 0; //first item in the stack
var queueArray = []; //array to hold items
}
Queue.prototype.add = function(obj) {
queueArray.push(obj);
}
Queue.prototype.get = function() {
return queueArray.splice(this.top, 1);
}
var queueArray = new Queue();
for (i = 0; i < tickerArray.length; i++) {
queueArray.add(tickerArray[i]);
}
console.log(q.get());
Set queueArray as this.queueArray and return this.queueArray from .get()
var tickerArray = ['BP', 'AMZN', 'EARK'];
function Queue() {
this.top = 0; //first item in the stack
this.queueArray = []; //array to hold items
}
Queue.prototype.add = function(obj) {
this.queueArray.push(obj);
}
Queue.prototype.get = function() {
this.queueArray.splice(this.top, 1);
return this.queueArray; // `return` `this.queueArray` from the function
}
var queueArray = new Queue();
for (i = 0; i < tickerArray.length; i++) {
queueArray.add(tickerArray[i]);
}
console.log(queueArray.get());
Related
Here is the constructor function, an 'push' function and an 'add' function.
function Erray() {
this.storage = {};
this.index = 0;
}
Erray.prototype.push = function(value) {
this.storage[this.index++] = value;
}
Erray.prototype.add = function(index, value) {
for (let i = index; i <= this.storage.length; i++) {
if (i === index) {
break;
}
this.storage[i] = this.storage[i - 1];
}
this.storage[index] = value;
}
The problem comes when I try to call the add method.
let array = new Erray;
array.push(1)
array.push(2)
array.push(3)
array.add(1,1)
I keep getting "arrray.add is not a function". Could you please tell me why? Thank you for your time!
Forgive me for what might be terrible javascript code. This is my first time trying something in javascript...
function Tile (window_id, size)
{
this.window_id = window_id;
this.size = size;
};
function Desktop ()
{
this.tiles = [];
this.ntiles = function () {return this.tiles.length;};
this.size = function ()
{
var sum = 0;
for (i = 0; i < this.ntiles(); i++) {sum += this.tiles[i].size;};
return sum;
};
this.addTile = function (tile)
{
if (this.size() === 1) {return -1;};
this.tiles.push(tile);
return 0;
};
};
function Layer ()
{
this.desktops = [];
this.ndesktops = function () {return this.desktops.length;};
this.addDesktop = function (desktop)
{
this.desktops.push(desktop);
return 0;
};
this.availableDesktopSize = function (size)
{
for (i = 0; i < this.ndesktops(); i++)
{
print(this.desktops[i].size());
print('hi');
print(this.desktops[i].size());
print('hihi');
var space = 1.0 - this.desktops[i].size();
print('hihihi');
print(space);
print(size);
if (space >= size) {return i;};
};
return -1;
};
};
var layer = new Layer();
var desktop1 = new Desktop();
var desktop2 = new Desktop();
var tile = new Tile(100, 0.5);
desktop1.addTile(tile);
desktop1.addTile(tile);
desktop2.addTile(tile);
layer.addDesktop(desktop1);
layer.addDesktop(desktop2);
print(layer.availableDesktopSize(0.51));
print(layer.availableDesktopSize(0.49));
I'm trying to make a method for the Layer class that finds the first desktop that has enough space left. In trying to achieve this, while trying my code, I observed that for some reason when I call the desktop.size() property I get the right value back the first time but when I call it a second time my script dies. This is the output
1
hi
TypeError: Result of expression 'this.desktops[i]' [undefined] is not an object.
So it does the first print fine but why can't it do the exact same function another time?
(If you have any other advice to improve my code, that would be very helpfull)
The problem is that you are using a global i variable in several loops.
You call a method from within such a loop, and that method has its own loop giving a different value to the same i variable. So when you come back from that call i no longer is the same as before.
Solution: declare your variables as local variables.
for (let i = 0; // ...etc
// ^^^
Use var to declare your iterator variable i to bind it to the scope. Now you're using a global scoped i that is causing trouble.
However in modern browsers let would be better because that binds the variable to the block scope. The current {} preventing the value of that variable to be used outside of that block.
function Tile (window_id, size)
{
this.window_id = window_id;
this.size = size;
};
function Desktop ()
{
this.tiles = [];
this.ntiles = function () {return this.tiles.length;};
this.size = function ()
{
var sum = 0;
for (var i = 0; i < this.ntiles(); i++) {sum += this.tiles[i].size;}; //var i binds i to this function scope.
return sum;
};
this.addTile = function (tile)
{
if (this.size() === 1) {return -1;};
this.tiles.push(tile);
return 0;
};
};
function Layer ()
{
this.desktops = [];
this.ndesktops = function () {return this.desktops.length;};
this.addDesktop = function (desktop)
{
this.desktops.push(desktop);
return 0;
};
this.availableDesktopSize = function (size)
{
for (var i = 0; i < this.ndesktops(); i++) //var i binds i to this function scope.
{
console.log(this.desktops[i].size());
console.log('hi');
console.log(this.desktops[i].size());
console.log('hihi');
var space = 1.0 - this.desktops[i].size();
console.log('hihihi');
console.log(space);
console.log(size);
if (space >= size) {return i;};
};
return -1;
};
};
var layer = new Layer();
var desktop1 = new Desktop();
var desktop2 = new Desktop();
var tile = new Tile(100, 0.5);
desktop1.addTile(tile);
desktop1.addTile(tile);
desktop2.addTile(tile);
layer.addDesktop(desktop1);
layer.addDesktop(desktop2);
console.log(layer.availableDesktopSize(0.51));
console.log(layer.availableDesktopSize(0.49));
I'm not positive but it seems to be the way i is assigned in your for loops.
in this bit of code
print(this.desktops[i].size());
print('hi');
print(this.desktops[i].size());
i is 0 but then is set to 2 in the line below
for (i = 0; i < this.ntiles(); i++) {sum += this.tiles[i].size;};
function Tile (window_id, size)
{
this.window_id = window_id;
this.size = size;
};
function Desktop ()
{
this.tiles = [];
this.ntiles = function () {return this.tiles.length;};
this.size = function ()
{
var sum = 0;
for (i = 0; i < this.ntiles(); i++) {sum += this.tiles[i].size;};
return sum;
};
this.addTile = function (tile)
{
if (this.size() === 1) {return -1;};
this.tiles.push(tile);
return 0;
};
};
function Layer ()
{
this.desktops = [];
this.ndesktops = function () {return this.desktops.length;};
this.addDesktop = function (desktop)
{
this.desktops.push(desktop);
return 0;
};
this.availableDesktopSize = function (size)
{
for (i = 0; i < this.ndesktops(); i++)
{
console.log(this.desktops[i].size());
console.log(i)
print('hi');
print(this.desktops[i].size());
print('hihi');
var space = 1.0 - this.desktops[i].size();
print('hihihi');
print(space);
print(size);
if (space >= size) {return i;};
};
return -1;
};
};
var layer = new Layer();
var desktop1 = new Desktop();
var desktop2 = new Desktop();
var tile = new Tile(100, 0.5);
desktop1.addTile(tile);
desktop1.addTile(tile);
desktop2.addTile(tile);
layer.addDesktop(desktop1);
layer.addDesktop(desktop2);
console.log(layer.availableDesktopSize(0.51));
console.log(layer.availableDesktopSize(0.49));
Need help with the chaining. The functions work. But async calls make it hard for me to get everything. Help me think right!
My thought:
Get All Webs recursively (function works)
Get all lists from webs and iff announcementlist add to array and pass along
Get two items from all announcmentlists and sort by created.
Add ALL announcement items into one large array (to be able to sort array later.
Heres the code,
function getAllWebs(success, error) {
var ctx = SP.ClientContext.get_current();
var web = ctx.get_site().get_rootWeb();
var result = [];
var level = 0;
result.push(web);
var getAllWebsInner = function (web, result, success, error) {
level++;
var ctx = web.get_context();
var webs = web.get_webs();
ctx.load(webs, 'Include(Title,Webs,ServerRelativeUrl)');
ctx.executeQueryAsync(
function () {
for (var i = 0; i < webs.get_count() ; i++) {
var web = webs.getItemAtIndex(i);
result.push(web);
if (web.get_webs().get_count() > 0) {
getAllWebsInner(web, result, success, error);
}
}
level--;
if (level == 0 && success)
success(result);
},
error);
};
getAllWebsInner(web, result, success, error);
}
function error(sender, args) {
console.log(args.get_message());
};
function getAnnouncementLists(web, success, error) {
var dfd = $.Deferred();
var ctx = web.get_context();
var collList = web.get_lists();
var result = []
ctx.load(collList, 'Include(Title, Id, BaseTemplate)');
ctx.executeQueryAsync(function () {
for (var i = 0; i < collList.get_count() ; i++) {
var list = collList.getItemAtIndex(i);
var bTemp = list.get_baseTemplate();
if (bTemp == 104) {
result.push(list);
}
}
//success(result);
dfd.resolve(result);
}, error);
return dfd.promise();
}
function getListItems(list, success, error) {
var dfd = $.Deferred();
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><OrderBy><FieldRef Name="Created" Ascending="False"></FieldRef>'
+ '</OrderBy></Query><ViewFields><FieldRef Name="Title"/><FieldRef Name="Body"/>' +
'<FieldRef Name="Created"/></ViewFields><RowLimit>2</RowLimit></View>');
var listItems = list.getItems(camlQuery);
var result = []
var ctx = list.get_parentWeb().get_context();
ctx.load(listItems);
ctx.executeQueryAsync(function () {
for (var i = 0; i < listItems.get_count() ; i++) {
var item = listItems.getItemAtIndex(i);
result.push(item);
}
dfd.resolve(result);
//success(result);
}, error);
return dfd.promise();
}
function printResults(items) {
var sortedItems = items.sort(dynamicSort("get_created()"));
alert(sortedItems);
}
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
$(document).ready(function () {
var items = getAllWebs(
function (allwebs) {
var array = [];
for (var i = 0; i < allwebs.length; i++) {
getAnnouncementLists(allwebs[i]).then(function (announceLists) {
for (var i = 0; i < announceLists.length; i++) {
getListItems(announceLists[i]).then(function (items) {
array.push(items);
});
}
});
}
return array;
}
);
//getAllWebs(
// function (allwebs) {
// for (var i = 0; i < allwebs.length; i++) {
// getAnnouncementLists(allwebs[i],
// function (announceLists) {
// for (var i = 0; i < announceLists.length; i++) {
// getListItems(announceLists[i],
// function (items) {
// printResults(items);
// }, error);
// }
// }, error);
// }
// }, error);
});
Given the requirements to retrieve list items from Announcements lists located across site collection, below is demonstrated the modified example that contains some improvements such as:
the number of requests to the server is reduced
fixed the issue in getAllWebs function that prevents to return any results if site contains only a root web
Example
function getAllWebs(propertiesToRetrieve,success, error) {
var ctx = SP.ClientContext.get_current();
var web = ctx.get_site().get_rootWeb();
var result = [];
var level = 0;
ctx.load(web, propertiesToRetrieve);
result.push(web);
var getAllWebsInner = function (web, result, success, error) {
level++;
var ctx = web.get_context();
var webs = web.get_webs();
var includeExpr = 'Include(Webs,' + propertiesToRetrieve.join(',') + ')';
ctx.load(webs, includeExpr);
ctx.executeQueryAsync(
function () {
for (var i = 0; i < webs.get_count() ; i++) {
var web = webs.getItemAtIndex(i);
result.push(web);
if (web.get_webs().get_count() > 0) {
getAllWebsInner(web, result, success, error);
}
}
level--;
if (level == 0 && success)
success(result);
},
error);
};
getAllWebsInner(web, result, success, error);
}
function loadListItems(lists,query,success,error,results){
var results = results || [];
var curList = lists[0];
var ctx = curList.get_context();
var listItems = curList.getItems(query);
ctx.load(listItems);
ctx.executeQueryAsync(function () {
results.push.apply(results, listItems.get_data());
lists.shift();
if(lists.length > 0) {
loadListItems(lists,query,success,error,results);
}
if(lists.length == 0)
success(results);
}, error);
}
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
var propertiesToRetrieve = ['Lists.Include(BaseTemplate)','ServerRelativeUrl'];
getAllWebs(propertiesToRetrieve,
function(allwebs){
//1. get filtered lists
var allAnnouncementLists = [];
allwebs.forEach(function(w){
var announcementLists = w.get_lists().get_data().filter(function(l){
if(l.get_baseTemplate() == SP.ListTemplateType.announcements)
return l;
});
allAnnouncementLists.push.apply(allAnnouncementLists, announcementLists);
});
//2.Load list items from lists
var query = new SP.CamlQuery(); //<-set your custom query here
loadListItems(allAnnouncementLists,query,
function(allListItems){
//3.Sort and print results
var sortedItems = allListItems.sort(dynamicSort("get_created()"));
sortedItems.forEach(function(item){
console.log(item.get_item('Title'));
});
},logError);
},
logError);
function logError(sender,args){
console.log(args.get_message());
}
I am using anonymous function assigned to a variable to minimize use of global variables. Within this function there are nested functions: one to preload and resize images, and two other nested functions for navigation (next and previous). The code below generates error that the variable to which the anonymous function is assigned is not defined:
Cannot read property 'preload_and_resize' of undefined
If you spot the problem please let me know. Thank you very much.
<html>
<head>
<script type="text/javascript">
var runThisCode=(function(){
var myImages=new Array("img/01.jpg","img/02.jpg","img/03.jpg");
var imageObj = new Array();
var index=0;
var preload_and_resize=function(){
var i = 0;
var imageArray = new Array();
for(i=0; i<myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
};
var next_image=function(){
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else{
index=0;
document.pic.src=imageObj[index].src;
}
};
var prev_image=function(){
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else{
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
};
})();
</script>
</head>
<body onload="runThisCode.preload_and_resize();">
<div align="center">
<img name="pic" id="pic" src="img/01.jpg"><br />
PrevNext
</div>
</body>
</html>
Your anonymous function doesn't return anything, so when you run it, undefined gets returned. That's why runThisCode is undefined. Regardless though, with the way you've written it, preload_and_resize will be local, so you wouldn't be able to access that anyway.
Instead, you want this anonymous function to construct an object, and reutrn that. Something like this should work, or at least get you close:
var runThisCode=(function(){
var result = {};
result.myImages=new Array("img/01.jpg","img/02.jpg","img/03.jpg");
result.imageObj = new Array();
result.index=0;
result.preload_and_resize=function(){
var i = 0;
var imageArray = new Array();
for(i=0; i< result.myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
};
result.next_image=function(){
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else{
index=0;
document.pic.src=imageObj[index].src;
}
};
result.prev_image=function(){
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else{
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
};
return result;
})();
This should explain what you are doing wrong :
var foobar = (function (){
var priv1, priv2 = 'sum' , etc;
return {
pub_function: function() {},
another: function() {
console.log('cogito ergo ' + priv2 );
}
};
})();
foobar.another();
You've assigned the function to the variable next_image which is scoped to the self-invoking anonymous function.
The value you assign to runThisCode is the return value of that anonymous function, which (since there is no return statement) is undefined.
To get the code to work you need to assign an object to runThisCode and make next_image a member of it.
Add the following to the end of the anonymous function:
return {
"next_image": next_image
}
Remove the anonymous function, and make your function public. You will only create one global variable: the object runThisCode.
var runThisCode = function () {
var myImages = new Array("img/01.jpg", "img/02.jpg", "img/03.jpg");
var imageObj = new Array();
var index = 0;
this.preload_and_resize = function () {
var i = 0;
var imageArray = new Array();
for (i = 0; i < myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src = myImages[i];
}
document.pic.style.height = (document.body.clientHeight) * 0.95;
};
this.next_image = function () {
index++;
if (index < imageObj.length) {
document.pic.src = imageObj[index].src;
} else {
index = 0;
document.pic.src = imageObj[index].src;
}
};
this.prev_image = function () {
index--;
if (index >= 0) {
document.pic.src = imageObj[index].src;
} else {
index = myImages.length - 1;
document.pic.src = imageObj[index].src;
}
};
};
And then, later in your code:
runThisCode.preload_and_resize();
should work.
From the invocation you've got in body onload property, it looks like what you're trying to achieve with the IIFE (immediately invoked function expression) is return an object that has a the method preload_and_resize.
As others have pointed out, you're not returning anything from the IIFE, so really all that's happening is you're closing up everything inside it in its own namespace, but not "exporting" anything.
If you want to "export" those functions, from your IIFE, you'd probably add a final bit to it that looked something like this:
return {
'preload_and_resize': preload_and_resize,
'next_image': next_image,
'prev_image': prev_image
}
which essentially creates a new JavaScript object literal, and then assigns its properties to the function values from the local scope.
Some developers would find this redundant and rather than finishing out with this sort of explicit export would probably just define the functions while declaring the object literal, something like:
return {
preload_and_resize: function(){
var i = 0;
var imageArray = new Array();
for(i=0; i<myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src=myImages[i];
}
document.pic.style.height=(document.body.clientHeight)*0.95;
},
next_image: function() {
index++;
if(index<imageObj.length){
document.pic.src=imageObj[index].src;
}
else {
index=0;
document.pic.src=imageObj[index].src;
}
},
prev_image: function() {
index--;
if(index>=0){
document.pic.src=imageObj[index].src;
}
else {
index=myImages.length-1;
document.pic.src=imageObj[index].src;
}
}
}
In respect of previous answers, my version:
function(self) {
let myImages = new Array("img/01.jpg", "img/02.jpg", "img/03.jpg");
let imageObj = new Array();
let index = 0; // if you need to expose this call with self.index
self.preload_and_resize = function() {
let i = 0;
let imageArray = new Array();
let (i = 0; i < myImages.length; i++) {
imageObj[i] = new Image();
imageObj[i].src = myImages[i];
}
document.pic.style.height = (document.body.clientHeight) * 0.95;
};
var next_image = function() {
index++;
if (index < imageObj.length) {
document.pic.src = imageObj[index].src;
} else {
index = 0;
document.pic.src = imageObj[index].src;
}
};
var prev_image = function() {
index--;
if (index >= 0) {
document.pic.src = imageObj[index].src;
} else {
index = myImages.length - 1;
document.pic.src = imageObj[index].src;
}
};
})(window.myCurrentPage = window.myCurrentPage || {});
// now you canll myCurrentPage.preload_and_resize();
I have this javascript snippet:
var selectName["id1","id2","id3"];
setOnClickSelect = function (prefix, selectName) {
for(var i=0; i<selectName.length; i++) {
var selId = selectName[i];
alert(selId);
$(selId).onchange = function() {
$(selId).value = $(selId).options[$(selId).selectedIndex].text;
}
}
}
But when I change value to my id1 element, the alert wrote me always "id3".
Can I fix it?
EDIT:
I've changed my snippet with these statements:
setOnChangeSelect = function (prefix, selectName) {
for(var i=0; i<selectName.length; i++) {
var selId = selectName[i];
$(selId).onchange = (function (thisId) {
return function() {
$(selId).value = $(thisId).options[$(thisId).selectedIndex].text;
}
})(selId);
}
}
But selId is always the last element.
This is caused by the behavior of javaScript Closure, selId has been set to the selectName[2] at the end of the loop and that's why you get 'id3' back.
An fix is as following, the key is wrap the callback function inside another function to create another closure.
var selectName = ["id1","id2","id3"];
var setOnClickSelect = function (prefix, selectName) {
for(var i = 0; i < selectName.length; i++) {
var selId = selectName[i];
$(selId).onchange = (function (thisId) {
return function() {
$(thisId).value = $(thisId).options[$(thisId).selectedIndex].text;
}
})(selId);
}
};
Ps: there is synyax error for var selectName["id1","id2","id3"], you should use var selectName = ["id1","id2","id3"];