Calling a Dynamically set Function Object Property from within the Object - javascript

From within my webpage I am creating an object and trying to call a dynamically set function from within it. The dynamic function however, isn't being executed.
Here is a subset of the Object:
var LightBoxLogin = {
DialogBox: null,
SuccessFunction: null,
..........
Login: function(){
console.log(LightBoxLogin.SuccessFunction) // Displays "TestSubmit()"
LightBoxLogin.SuccessFunction(); // does nothing, should alert the page
}
}
LightBoxLogin.SuccessFunction is set with:
function SuperLightbox(functOnSuccess)
{
LightBoxLogin.SuccessFunction = functOnSuccess;
if(IsLightboxNeeded())
{
LightBoxLogin.Login();
}
else{
alert("Not needed");
}
}
And called like:
function TestSubmitHandler ()
{
SuperLightbox(TestSubmit);
}
function TestSubmit ()
{
alert('TEST SUBMIT ALL CAPS');
}
Let me know if im missing anything.
I just need to execute the function passed as a parameter initially.

Instead of the line
SuperLightBox(TestSubmit);
Use the function name as a String instead:
SuperLightBox("TestSubmit");
This means in the Login:function() this line:
LightBoxLogin.SuccessFunction();
Will be replaced with:
window[LightBoxLogin.SuccessFunction]();
This yields the results I was looking for, but beware; it only works if the desired function is accessible globally in the page.

Related

How to use Callback functions in Class with JavaScript/jQuery

I have a class I am using for creating CRUD Objects for my site.
It stores the form and table paths for adding, listing, editing and deleting the data, as well as reloading your view with ajax after each edit.
Here is my class definitions:
class CRUDObj{
constructor(containerSel, links) {
this.links = links;
this.containerSel = containerSel;
this.formCallBack = function(){};
}
setActive(obj_id){
$.post(this.links.editURL+'?'+obj_id, {status:"active"}, this.reload);
}
reload(returnData){
this.formCallBack(returnData);
this.formCallBack = function(){};
if($(this.containerSel).length > 0){
ajaxLoad(this.links.listURL, $(this.containerSel));
}
}
}
A basic instance of initializing it:
var contactObj = new CRUDObj('#contacts', {
editURL: '/contact.edit.php',
listURL: '/contacts.list.php',
});
contactObj.formCallBack = function(){
console.log('Custom Reload Callback');
};
The problem appeared when I tried to add the callback, so that I could run a custom function during the refresh.
Running contactObj.setActive(); works properly, and my refresh function is called after the form submits, but when it hits my callback I get:
Uncaught TypeError: this.formCallBack is not a function
Calling it manually contactObj.refresh(); works smoothly.
How can I pass this callback function through better?
The problem is that you're passing method as function, so you loose this context. this will be window object or undefined (if using strict mode):
You need this:
var self = this;
lightboxForm(this.links.editURL+'?'+obj_id, function(x) { self.reload(x) });
or using ES6
lightboxForm(this.links.editURL+'?'+obj_id, x => this.reload(x));
or using bind to return function with given context:
lightboxForm(this.links.editURL+'?'+obj_id, this.reload.bind(this));

Function not being set correctly

I have a function that creates a new record in the database and returns the ID of the record created. From this I need to assign a function to a select with the value of the returned ID.
.done(function(response) {
//console.log(siblings[1].dataset.contno);
var dbResponse = JSON.parse(response);
document.getElementById(runID).setAttribute('data-runid', dbResponse.id);
var newRunID = dbResponse.id;
var driverSelectID='driverSelectRun'+runCode;
//adding the onchange function with the correct ID to the dropdowns (the assignVehicle FUnction takes the runID which is unknown untill response)
(function(newRunID) {
document.getElementById(driverSelectID).onchange = function () {
assignDriver(newRunID);
}
})(newRunID);
(function(newRunID) {
document.getElementById(vehicleSelectID).onchange = function () {
assignVehicle(newRunID);
}
})(newRunID);
console.log(newRunID);
});
The console.log for the newRunID is 1566 but the onchange function of this select does not contain the new run id it simply shows as assignVehicle(newRunID) instead of actually using the value returned from the database (assignVehicle(1566)). I have used the exact same method on another part of the code which works fine. Can anyone see why this is not working correctly.
Thanks in advance for any replies!
<select id="driverSelectRun6">...</select>
That is the code for the select. It is definately being targeted correctly as the function is being set just without the arguement.
UPDATE
This was a scope issue. The newRunID was declared using var newRunID= but this was delcared in the .done function so was of local scope instead of global. removing the var to make it just newRunID= worked because assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object)
The issue here is you are redefining the variable newRunID as an argument and that argument is actually the event object that is returned from the change event listener.
.onchange = function (newRunID) {
should be
.onchange = function () {
(function(newRunID) {
document.getElementById(driverSelectID).onchange = function () {
assignDriver(newRunID);
}
})(newRunID);

Object properties not updated

I have an object with a function that updates the variables of the object. I would like to use this function as a constructor too, so I can define the properties inside it. If I only define the properties within this function other functions don't realize about the change.
I mean, this.property returns undefined.
The object looks like this:
function LastRow_(sheet)
{
var lastCol,firstRowVals,rowNumber,headers;
this.rowValues;
updateObject();
// Logger.log(headers);
/*Returns the value of a specific column within last row.
It accepts header name or column letter in A1 notation*/
this.getColValue=function(column)
{
updateObject();
Logger.log(this.rowValues);
var index=getColNumber(column);
if(index>-1) return this.rowValues[index];
Logger.log("Can't find header, trying with: "+column+rowNumber);
return sheet.getRange(column+rowNumber).getValue();
};
this.setColValue=function(column,value)
{
updateObject();
};
function getColNumber(colName){ return headers.indexOf( colName.toLowerCase() ); }
/*This function is to be sure that you are allways working with the last row
and an updated version of the headers*/
function updateObject()
{
if(lastCol!==sheet.getLastColumn())
{
Logger.log("Updating row Headers");
lastCol=sheet.getLastColumn();
firstRowVals=sheet.getRange(1,1,1,lastCol).getValues()[0];
headers=[];
for(var i=0;i<firstRowVals.length;i++)
headers.push(firstRowVals[i].toLowerCase());
Logger.log(headers);
}
if(rowNumber!==sheet.getLastRow())
{
Logger.log("Updating row Values");
rowNumber=sheet.getLastRow();
this.rowValues=sheet.getRange(rowNumber,1, 1, lastCol).getValues()[0];
Logger.log(this.rowValues);
}
};
}
Any call to the object methods produces the error
function test() {/*valueLastRow(SpreadsheetApp.getActiveSpreadsheet().getSheetByName('workedDays'),"C",5)*/
var LastRow=new LastRow_(SpreadsheetApp.getActiveSpreadsheet().getSheetByName('workedDays'));
Logger.log(LastRow.getColValue("D"));
Logger.log(LastRow.getColValue("sede"));
}
The problem is that this.rowNumber is undefined.
Thanks in advance.

Using an anonymous function as part of a javascript object

I'm going to show you two snippets.
This works fine:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: processSearchResults
});
This doesn't work at all:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: function() {
processSearchResults
}
});
I need to place that processSearchResults call inside an if statement, to check if my search text input ($('.search')) has any text written inside it.
My first idea was to use this function type notation, but it's not working. It's as if the call to processSearchResults is never made at all.
Any suggestions?
That's because you do not actually call that function. This would be correct:
this.searchBox = new Foo.UI.SearchBox(this.input, {
autoCompleteSearchComplete: function() {
if (...) {
processSearchResults();
}
}
});

how to get the value from a callback function

I am relatively new to javascript and I am facing some difficulty.I have two java script files as I have shown below. I am having trouble getting the value of the variable entry_title inside the getRss function and storing it inside the variables Rss1_title and Rss2_title . Creating a global variable and assigning it to entry_title will make things worse as I will not be able to know from which Rss url the title came from. Is there a easy way to get the value of the callback functions ?
<script type="text/javascript" src="jsRss.js"></script>
<script type="text/javascript" src="notification.js"></script>
My notification.js file
function get_rss1_feeds(){
var Rss1_title = getRss("http://yofreesamples.com/category/free-coupons/feed/?type=rss");
}
function get_rss2_feeds(){
var Rss2_title = getRss("http://yofreesamples.com/category/real-freebies/feed/?type=rss");
}
setTimeout('get_rss1_feeds()',8000);
setTimeout('get_rss2_feeds()',7000);
My jsRss.js file:
function getRss(url){
if(url == null) return false;
google.load("feeds", "1");
// Our callback function, for when a feed is loaded.
function feedLoaded(result) {
if (!result.error) {
var entry = result.feed.entries[0];
var entry_title = entry.title; // need to get this value
}
}
function Load() {
// Create a feed instance that will grab feed.
var feed = new google.feeds.Feed(url);
// Calling load sends the request off. It requires a callback function.
feed.load(feedLoaded);
}
google.setOnLoadCallback(Load);
}
Errors :
When the setTimeout(get_rss1_feeds, 8000); method is called I get a blank screen.
I get a error in my console saying octal literals and octal escape sequences are deprecated and it is pointing to the 6th line in this script.
Is it because I am using google-api for parsing my Rss?
if (window['google'] != undefined && window['google']['loader'] != undefined) {
if (!window['google']['feeds']) {
window['google']['feeds'] = {};
google.feeds.Version = '1.0';
google.feeds.JSHash = '8992c0a2cdf258e5bd0f517c78243cd6';
google.feeds.LoadArgs = 'file\75feeds\46v\0751';
}
google.loader.writeLoadTag("css", google.loader.ServiceBase + "/api/feeds/1.0/8992c0a2cdf258e5bd0f517c78243cd6/default+en.css", false);
google.loader.writeLoadTag("script", google.loader.ServiceBase + "/api/feeds/1.0/8992c0a2cdf258e5bd0f517c78243cd6/default+en.I.js", false);
}
Seeing as it's a different scope, you can either return it in a callback, or provide it in another way such as exporting it to a higher scope that is visible to your desired location. In this case, it's the global scope, so I'd advise against that.
function getRss(url, callback) {
//...
function feedLoaded(result) {
if (!result.error) {
var entry = result.feed.entries[0];
var entry_title = entry.title; // need to get this value
callback && callback(entry_title);
}
}
and call it like so,
function get_rss1_feeds() {
var Rss1_title = getRss("http://yofreesamples.com/category/free-coupons/feed/?type=rss", function(entry_title) {
// This scope has access to entry_title
});
}
As an aside, use your setTimeout like so:
setTimeout(get_rss1_feeds, 8000);
rather than
setTimeout("get_rss1_feeds()", 8000);
as the latter uses eval, whereas the former passes a reference to the function.
Eventhough it will make your code a mess, you can append the variables to the window object.
For example:
function a()
{
window.testStr = "test";
}
function b()
{
alert(window.testStr);
}
Or even create your own object, instead of using window, as such:
var MyRSSReader = {
TitleOne : '',
TitleTwo : ''
}
MyRSSReader.TitleOne = "My title";
Wikipedia has a nice article about global variables, and why they are bad.

Categories