How to access a method in one object from a second object - javascript-objects

Hi I'm new to javascript. I have one object ListModel and I am trying to access the addToModel method from a second object.
function ListModel(){
this.list = {};
}
ListModel.prototype.addToModel = function(s){
var items = s.split("\n");
for( var i =0; i<items.length-1; i++){
console.log(items[i] + "\n");
}
}
After extensive searching I have been unable to find a solution to this problem.
The second object is:
function ListMaker(){
this.model = new ListModel();
}
ListMaker.prototype.read = function(e){
var f = e.target.files[0];
if (f) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
this.model.addToModel(contents);
document.getElementById("ta").innerHTML = contents;
}
r.readAsText(f);
} else {
alert("Failed to load file");
}
}
In the read method I call:
this.model.addToModel(contents);
and the console returns
Cannot read property 'addToModel' of undefined
If I change the line to:
this.model = new ListModel().addToModel(contents);
then the method works as excpected.
Maybe I'm going about this the wrong way.
Any help would be appreciated.

The problem is this
http://javascriptplayground.com/blog/2012/04/javascript-variable-scope-this/
Once you call a function, this is no longer pointing to what you think it is.
You need to stash this in a local and then reference the local in your callback.
ListMaker.prototype.read = function(e){
var f = e.target.files[0];
var _this = this;
if (f) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
_this.model.addToModel(contents);
document.getElementById("ta").innerHTML = contents;
}
r.readAsText(f);
} else {
alert("Failed to load file");
}
}
See it in action: http://codepen.io/anon/pen/eZrYQj

Related

Issue with Google Apps Script code copy-paste from Gsheet file

I've created a code to copy-paste the values from the most recent uploaded Gsheet file to another. The code is supposed to copy-paste only values that fulfil a cell condition.
The problem is, this code takes to long to run and doesn't finish to copy all values before having a run-time error.
The file has about 300.000 cells and the final amounts to be pasted on the 2nd file have about 90.000 cells.
Does anyone have a recommendation on how to proceed?
Thank you so much for your kind support.
function Master_Run_DB() {
Copy_EUDB();
}
function Copy_EUDB() {
var myLink = extractLink_EUDB();
sendData_EUDB(myLink);
}
function extractLink_EUDB() {
var newData = new Date().toLocaleString();
var drive = DriveApp.getFolderById("link to file");
var file = drive.getFilesByType(MimeType.GOOGLE_SHEETS);
var link = file.next().getUrl();
var ss = SpreadsheetApp.getActiveSpreadsheet();
return link
}
function sendData_EUDB(link) {
var mainSS = SpreadsheetApp.openById("link to file");
var lastRow = mainSS.getSheetByName("Database").getLastRow();
mainSS.getSheetByName("Database").getRange("A2" + ":R" + lastRow).clearContent();
var baseSS = SpreadsheetApp.openByUrl(link);
Logger.log(SpreadsheetApp.getActiveSpreadsheet().getUrl());
var lRow = baseSS.getSheetByName("Sheet1").getLastRow();
for (var i = 2; i <= lRow; i++) {
var cell = baseSS.getRange("G" + i);
var val = cell.getValue();
if (val == "EU") {
var sourceData = baseSS.getSheetByName("Sheet1").getRange("A" + i + ":R" + i).getValues();
var to = mainSS.getSheetByName("Database").getRange("A" + i + ":R" + i).setValues(sourceData);
}
}
};
Hello again,
Now that the new code is working, I was trying to add an IF AND clause to the copy-paste. The objective would be to copy only values that fulfil the following condition:
Column 7 = "EU"
Column 11 <> "CCCC"
But I'm getting a Syntax Error. Any advice?
Thank you in advance for your kind support
function Master_Run_EU() {
var drive = DriveApp.getFolderById("link to file");
var file = drive.getFilesByType(MimeType.GOOGLE_SHEETS);
var link = file.next().getUrl();
var ss = SpreadsheetApp.openById("link to file");
const sh=ss.getSheetByName('Database');
sh.getRange(2,1,sh.getLastRow(),22).clearContent();
var dbss = SpreadsheetApp.openByUrl(link);
const dbsh=dbss.getSheetByName('Sheet1');
var oA=[];
var vs=dbsh.getRange(2,1,dbsh.getLastRow()-1,22).getValues();
vs.forEach(function(r,i){
if(r[7]=="EU" && r[11]<>"CCCC") {
oA.push(r);
}
});
sh.getRange(2,1,oA.length,oA[0].length).setValues(oA);
}
Try this:
function Master_Run_DB() {
var drive = DriveApp.getFolderById("1ViOyzIkGOI6G6SMrtmPv4vjL-2-2duHC");
var file = drive.getFilesByType(MimeType.GOOGLE_SHEETS);
var link = file.next().getUrl();
var ss = SpreadsheetApp.openById("13CchyoqiWyvGTnYuG5TWA4cggBS-FsoDkW8XGesDkiY");
const sh=ss.getSheetByName('Database');
sh.getRange(2,1,sh.getLastRow(),18).clearContent();
var dbss = SpreadsheetApp.openByUrl(link);
const dbsh=dbss.getSheetByName('Sheet1');
var vs=dbsh.getRange(2,1,dbsh.getLastRow()-1,18).getValues();
vs.forEach(function(r,i){
if(r[6]=="EU") {
sh.getRange(i+2,1,1,18).setValues([r]);
}
});
}
It would be faster to do it this way:
function Master_Run_DB() {
var drive = DriveApp.getFolderById("1ViOyzIkGOI6G6SMrtmPv4vjL-2-2duHC");
var file = drive.getFilesByType(MimeType.GOOGLE_SHEETS);
var link = file.next().getUrl();
var ss = SpreadsheetApp.openById("13CchyoqiWyvGTnYuG5TWA4cggBS-FsoDkW8XGesDkiY");
const sh=ss.getSheetByName('Database');
sh.getRange(2,1,sh.getLastRow(),18).clearContent();
var dbss = SpreadsheetApp.openByUrl(link);
const dbsh=dbss.getSheetByName('Sheet1');
var oA=[];
var vs=dbsh.getRange(2,1,dbsh.getLastRow()-1,18).getValues();
vs.forEach(function(r,i){
if(r[6]=="EU") {
oA.push(r);
}
});
sh.getRange(2,1,oA.length,oA[0].length).setValues(oA);
}

function never ends - fileReader xlsx.js angularJS

I'm using the FileReader Object in combination with xlsx.js to import data from an Excel-Sheet into my AngularJS Web-App.
The function never gets ended, so I need to continue the script manually by invoking an empty dummy function check(){} manually by clicking on a button to continue my script. I don't know, why the script behaves like that.
Code of my controller:
$scope.fileChanged = function(files) {
var i,f;
f = files[0];
reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, {type: 'binary'});
formData.data.teams = XLSX.utils.sheet_to_json(workbook.Sheets['latusch']);
var sheet_name_list = workbook.SheetNames;
var worksheet = workbook.Sheets['latusch'];
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}
});
reader.readAsArrayBuffer(f);
}
readAsArrayBuffer is inside the onload callback, so it will not be called.
Remove it from the callback.

How to extend returned objects in the list returned by $asArray?

I'm having trouble decorate the objects in my list returned by $asArray in angularfire with a new method (not decorating the array itself).
The angularfire documentation seems to suggest that the right way to do this is to override the $$added method in the factory for $FirebaseArray, returning a new object that either encapsulates or extends the snapshot that gets passed in to that method. From the documentation:
// an object to return in our JokeFactory
app.factory("Joke", function($firebaseUtils) {
function Joke(snapshot) {
this.$id = snapshot.name();
this.update(snapshot);
}
Joke.prototype = {
update: function(snapshot) {
// apply changes to this.data instead of directly on `this`
this.data = snapshot.val();
},
makeJoke: function() {
alert("Why did the " + this.animal + " cross the " + this.obstacle + "?");
},
toJSON: function() {
// since we didn't store our data directly on `this`, we need to return
// it in parsed format. We can use the util function to remove $ variables
// and get it ready to ship
return $firebaseUtils.toJSON(this.data);
}
};
return Joke;
});
app.factory("JokeFactory", function($FirebaseArray, Joke) {
return $FirebaseArray.$extendFactory({
// change the added behavior to return Joke objects
$$added: function(snap) {
return new Joke(snap);
},
// override the update behavior to call Joke.update()
$$updated: function(snap) {
this.$getRecord(snap.name()).update(snap);
}
});
});
However, when I do this in my code, nothing ever gets added to the array, although I can see from outputting to the console that it is getting called.
var printMessageObjConstructor = function(snap) {
this.$id = snap.name();
this.snapshot = snap;
this.$update = function(snap) {
this.snapshot = snap;
};
this.printMessage = function() {
return this.author + "'s question is: " + this.body;
};
};
var ref = new Firebase("https://danculley-test.firebaseio.com/questions");
//What Am I Doing Wrong Here?
var arrayFactory = $FirebaseArray.$extendFactory({
$$added: function(snap, prevChild) {
var x = new printMessageObjConstructor(snap);
console.log("I am being called from FirebaseDecoratedCtlOverloadAddedinNewObj.");
return x;
},
$createObject: function(snap) {
return new printMessageObjConstructor(snap);
},
$$updated: function(snap) {
var i = this.$indexFor(snap.name());
var q = this.$list[i];
q.$update(snap);
}
});
var sync = $firebase(ref, {arrayFactory:arrayFactory});
var list = sync.$asArray();
list.$loaded(function(list) {
$scope.questions = list;
});
I've set up a new plunk stripped down to show the issue with a couple other use cases that I've tried. (The actual method I'm adding is more complex and isn't related to the view, but I wanted to do something simple to reproduce the issue.)
I think the issue is that I don't quite understand what exactly $$added is supposed to return, or what additional behavior beside returning the value to be stored $$added is supposed to have. There also doesn't really seem to be an $$added on the prototype or on $FirebaseArray to call as a super to get the default behavior. Can someone point me in the right direction?
UPDATE
For the benefit of others, after reviewing the like that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}
For the benefit of others, after reviewing the link that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}

How to get the image dimension with angular-file-upload

I'm currently using the angular-file-upload directive, and I'm pretty much using the exact codes from the demo.
I need to add a step in there to test for the dimension of the image, and I am only currently able to do with via jQuery/javascript.
Just wondering if there's a "angular" way to check for the dimension of the image before it's being uploaded?
$scope.uploadImage = function($files) {
$scope.selectedFiles = [];
$scope.progress = [];
if ($scope.upload && $scope.upload.length > 0) {
for (var i = 0; i < $scope.upload.length; i++) {
if ($scope.upload[i] !== null) {
$scope.upload[i].abort();
}
}
}
$scope.upload = [];
$scope.uploadResult = [];
$scope.selectedFiles = $files;
$scope.dataUrls = [];
for ( var j = 0; j < $files.length; j++) {
var $file = $files[j];
if (/*$scope.fileReaderSupported && */$file.type.indexOf('image') > -1) {
var fileReader = new FileReader();
fileReader.readAsDataURL($files[j]);
var loadFile = function(fileReader, index) {
fileReader.onload = function(e) {
$timeout(function() {
$scope.dataUrls[index] = e.target.result;
//------Suggestions?-------//
$('#image-upload-landscape').on('load', function(){
console.log($(this).width());
});
//-------------------------//
});
};
}(fileReader, j);
}
$scope.progress[j] = -1;
if ($scope.uploadRightAway) {
$scope.start(j);
}
}
};
I think you can do it by:
var reader = new FileReader();
reader.onload = onLoadFile;
reader.readAsDataURL(filtItem._file);
function onLoadFile(event) {
var img = new Image();
img.src = event.target.result;
console.log(img.width, img.height)
}
This is the code snippet copied from https://github.com/nervgh/angular-file-upload/blob/master/examples/image-preview/directives.js.
I think this is more angularjs. However, you may need to modify it to fit your requirement.
Try this code
uploader.filters.push({
name: 'asyncFilter',
fn: function(item /*{File|FileLikeObject}*/ , options, deferred) {
setTimeout(deferred.resolve, 1e3);
var reader = new FileReader();
reader.onload = onLoadFile;
reader.readAsDataURL(item);
function onLoadFile(event) {
var img = new Image();
img.onload = function(scope) {
console.log(img.width,img.height);
}
img.src = event.target.result;
}
}
});

javascript: when declaring a prototype method: error is invalid left hand side for assignment

I am new to object oriented javascript. Trying to make an object constructor.
Here is my code
function Collection() {
this.ports = build_ports_collection();
this.all_things = build_things_collection();
this.added_things = function() {
this.added_things.total_added = 0;
var temp = this.all_things;
temp.splice($(sth).val(), 1);
this.added_things.all = temp;
};
};
Collection.ports.prototype.reload = function() {
Collection.ports = build_ports_collection();
};
Collection.all_things.prototype.reload = function() {
Collection.all_things = build_things_collection();
};
Collection.added_things.all.prototype.reload() = function() {
var temp = Collection.all_things;
temp.splice($(sth).val(), 1);
Collection.added_things.all = temp;
};
Collection.added_things.prototype.add_things = function() {
this.added_things.total_added++;
add_things();
};
Collection.added_things.prototype.remove_things = function() {
this.added_things.total_added--;
remove_things();
};
I am getting error in the line Collection.added_things.all.prototype.reload()=....
netbeans reports: invalid left hand side for assignment.
here my intention was to bind a method reload() to Collection.added_things.all so that it will be shared among all instances of Collection
What point i am missing ?
Not sure if this is the answer you're looking for, but this came to mind.
Collection.added_things.all.prototype.reload() = function() {
var temp = Collection.all_things;
temp.splice($(sth).val(), 1);
Collection.added_things.all = temp;
};
There, you are assigning stuff to the prototype of Collection.added_things.all, while
this.added_things = function() {
this.added_things.total_added = 0;
var temp = this.all_things;
temp.splice($(sth).val(), 1);
this.added_things.all = temp;
};
is the first to declare the .all on Collection.added_things - basically, you are trying to assign a value to a property/variable/pointer that does not exist until added_things is first called.

Resources