I'm using slickgrid as container for data, and trying to subscribe on it's onscroll event as of described in documentation, i.e.
task_list.onscroll.subscribe(function(e, args) {
console.log('scrolling occured');
});
Actually, I'm trying to do other processing afterwards, which is translating contents of the web page. The content is not fully translated, so I need to translate each time I scroll the page. However I get the message
Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')
How can I troubleshoot this error and find out why I get it?
There's a few small errors in your code, first the event names are camelCase so it should be onScroll and second if you want to subscribe to SlickGrid events then you need to use the grid object
grid.onScroll.subscribe(function(e, args) {
// ...
});
and don't forget to unsubscribe when leaving the page because you'll have quite a leak with the onScroll. I prefer to use the Slick EventHandler since it has an easier unsubscribeAll method that I can use when destroying/leaving the page
var eventHandler = new Slick.EventHandler();
var grid = new Slick.Grid("#myGrid", dataView, columns, options);
function something() {
eventHandler.subscribe(grid.onScroll, function(e, args) {
// ...
});
}
function destroy() {
eventHandler.unsubscribeAll();
}
Hopefully there's no error in my code but just to let you know I wrote by memory here so please double-check the code and look at the multiple SlickGrid Examples which all have easy code access
As an exercise I have to do a little online bike reservation app. This app begins with a header which explains how to use the service. I wanted this tutorial be optional so I wrote a welcome message in HTML and if the user doesn't have a var in his cookies saying he doesn't want to see the tutorial again, the welcome message is replaced by a slider that displays the information.
To achieve that is fetch a JSON file with all the elements I need to build the slider (three divs : the left one with an arrow image inside, the central one where the explanations occur and the right one with another arrow). Furthermore I want to put "click" events on the arrows to display next or previous slide. However, when I do so, only the right arrow event works. I thought of a closure problem since it is the last element to be added to the DOM that keeps its event but tried many things without success. I also tried to add another event to the div that works ("keypress") but only the click seems to work. Can you look at my code give me an hint on what is going on?
Here is the init function of my controller:
init: function() {
var load = this.getCookie();
if(load[0] === ""){
viewHeader.clearCode();
var diapoData = ServiceModule.loadDiapoData("http://localhost/javascript-web-srv/data/diaporama.json");
diapoData.then(
(data) => {
// JSON conversion
modelDiapo.init(data);
// translation into html
controller.initElementHeader(modelDiapo.diapoElt[0]);
controller.hideTuto();
}, (error) => {
console.log('Promise rejected.');
console.log(error);
});
} else {
viewHeader.hideButton();
controller.relaunchTuto();
}
}
There is a closer look at my function translating the JSON elements into HTML and adding events if needed :
initElementHeader: function(data){
data.forEach(element => {
// Creation of the new html element
let newElement = new modelHeader(element);
// render the DOM
viewHeader.init(newElement);
});
}
NewElement is a class creating all I need to insert the HTML, viewHeader.init() updates the DOM with those elements and add events to them if needed.
init: function(objetElt){
// call the render
this.render(objetElt.parentElt, objetElt.element);
// add events
this.addEvent(objetElt);
},
Finally the addEvent function:
addEvent: function(objet){
if(objet.id === "image_fleche_gauche"){
let domEventElt = document.getElementById(objet.id);
domEventElt.addEventListener("click", function(){
// do things
});
}
else if(objet.id === "image_fleche_droite"){
let domEventElt = document.getElementById(objet.id);
domEventElt.addEventListener("click", function(){
// do stuff
});
};
},
I hope being clear enough about my problem. Thank You.
Ok, I found the problem, even if the element was actually created, it somehow stayed in the virtual DOM for some time, when the "getElementById" in "addEvent" was looking for it in the real DOM it didn't find the target and couldn't add the event. This problem didn't occur for the last element since there was nothing else buffering in the virtual DOM.
On conclusion I took out the function adding events out of the forEach loop and created another one after the DOM is updated to add my events.
I know this subject has been already discussed in similar topics, but none of the solutions I could find can help me understand the issue I have.
Here is my simplified class and its the usual was I define them.
BottomNav = function() {
this.init();
}
$.extend(BottomNav.prototype, {
init: function(){
this.insue = false;
$(".up").click($.proxy(function () {
var thisinuse = this.inuse;
if(this.inuse===false) {
this.inuse = true;
this.moveSlider('up');
}
},this));
},
moveSlider: function(d){
//some instructions
alert('move slider');
}
});
$(document).ready(function() {
new BottomNav();
});
In FireBug on the breakpoint inside the click event this.inuse is undefined! (this is my problem), my scope looks good on the watch (right panel of firebug), this.insue is false as it should be - sorry I cannot post images yet!
I would be grateful of someone might help identifying this very strange behavior.
I tried some staff like putting the click event definition inside another function but it does not work either. I tried different ways of bindings and it does not work too.
However the below example is working on a number of other classes I made. I could access class scope from events, effects.
It's just a typo:
this.insue = false;
Change insue to inuse and the property will be there :-)
Apart from that, the variable thisinuse is quite superfluous in here. And change the condition to if(! this.inuse) instead of comparing to booleans…
this.inuse can be assigned to a variable out side your click event handler and use the variable inside the handler.
I am in deep trouble with my new requirement.
Suppose there is a form opened in Firefox & IE [Form contains some list of question and a textbox for asking question]. Now if i add some new question [in the Firefox], it needed to be displayed within a few second in the other browsers too [without refreshing the page].
I have tried to call a ajax page using setTimeout. But the problem is i can't use the innerhtml after getting the response from Ajax page. Think about the situation when a user tried to add something on a different browser when the innerHTML inside the ajax call overwrite the page . Please suggest a solution. :(
EDIT:
var auto_refresh = setInterval( function (){
$.post("something.php", { proj_id: $('#proj_id').val() }, function (data) {
if(data) { //alert(data); $('#autoRef').html(data).fadeIn("slow"); } },"html");
},
1000);
Right then, I'm coming to the end of a rewrite of our JavaScript system, we're moving from Prototype to jQuery. We have a load of AJAX requests that fire when a certain element events occur, the one in the example below is a new event on a calendar, but it happens elsewhere too.
The problem I'm getting is when an event is fired sometimes two AJAX requests are made. The first one returns the correct value but (as you can see) it still says processing, it never returns the success message my JavaScript requires. The second request returns the correct result AND terminates correctly.
The problem I have is our jQuery screen blocker is set up to prevent user input during heavy AJAX requests, obviously because there an AJAX request still live the screen never unlocks. If I were to refresh this screen all will work as desired.
Can anyone shed any light on why this behavior is occuring.
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request.png
EDIT
"requests that fire when a certain element events occur" - this is the key phrase, I think. Please provide some info on how you set your events. Maybe it fires twice because you have multiple handlers set? – Igor Zinov'yev
Ok, the thing is when I hit refresh the problem usually resolves itself, so not sure how that could be a handler issue, here's the event handler we typically use for a change of a select box.
$("#my_select","#context").change(function(){
// uz_ajax is a wrapper function, keeps most of the same functionality as $.ajax()
uz_ajax({
target:"#my_target",
data:{
module:'my_module',
controller:'my_controller',
action:'my_action',
id:$(this).val(),
ajax:''
}
});
});
The problem I have is I have no idea how to replicate the problem, so I do not know if the event is being fired multiple times or whether the AJAX is requesting twice.
EDIT 2
If you are reloading the elements that
are bound then the change events could
be triggered recursively... We really
need to see more code (what do you do
on success of the ajax call etc) –
redsquare
Thanks redsquare, upon a successful AJAX request I usually apply the response (usually HTML of <option>s) to the target. I never trigger a change from the element that fired the AJAX, but I sometimes trigger a change on the target element, to allow for cascading AJAX requests. If this were the problem, surely this would happen all the time? My wrapper function uz_ajax is below:
var ajax_count = 0;
var ajax_response = null;
function uz_ajax(options) {
// set default options
var defaults = {
async: true,
type: "GET",
data: {},
url: "/",
cache: false,
force_change: true,
highlight: true,
action: "normal",
dataType: "html",
selected: {
value: null,
disabled: false
}
};
// merge the passed options with the defaults
var options = $.extend(defaults, options);
// start the jQuery ajax method
$.ajax({
async: options.async,
type: options.type,
url: options.url,
data: options.data,
beforeSend: function() {
// we only want to block the screen on the first pass
if(++ajax_count==1) {
$.blockUI({message:'Loading data, please wait'});
}
},
success: function(responseText) {
if(options.target!==undefined) {
// if target isn't an array, make it one
if(!$.isArray(options.target)) {
options.target = new Array(options.target);
}
var targets = options.target;
for ( var i in targets ) {
console_info("uz_ajax() --> Applying contents to "+targets[i]);
switch(options.action) {
case "normal":
if($(targets[i]).is("input")) {
$(targets[i]).val(trim(responseText));
} else {
$(targets[i]).html(trim(responseText));
}
break;
case "selected":
// preserve the current target value (e.g. list of options), but
// set the selected value to the ajax response
console_warn("Changing selected value of "+targets[i]+" to '"+responseText+"'");
// trim the response so we don't get any smarty induced errors such as ' 7'
$(targets[i]).val(trim(responseText));
break;
}
// set selected value
if(options.selected.value!=null) {
$(targets[i]).val(options.selected.value);
}
// highlight the target
// we don't want to highlight the target if it's a hidden input, as this will force a .show(
if($(targets[i]).attr('type')!='hidden' && options.highlight===true) {
$(targets[i]).effect("highlight",{},2000);
}
// force the target to change
if(options.force_change===true) {
$(targets[i]).trigger("change");
}
/* rebind certain elements that do not use conventional events */
/* We probably need to get all of these rebinds in a single function */
createDatePickers(targets[i]);
}
} else {
ajax_response = responseText;
console_warn("uz_ajax -> no targets specified");
// Well... we have no element to target, we need to return the value instead
// of course if we return here we're going
// we probably also need to check the ajax count as this will be the last executed part before we return
}
},
complete: function () {
/* if all ajax requests have completed, unblock screen */
if(--ajax_count===0) {
$.unblockUI();
/* could use this callBack to return a value *dun dun duuuuun* */
if (options.ajaxComplete) {
options.ajaxComplete(ajax_response);
}
}
},
cache: options.cache,
dataType: options.dataType
});
}
another way to stop multiple ajax
requests is to heck jQuery.active
prior to the call. jQuery keeps an
internal count of 'live' ajax requests
using this property. – redsquare
I'll look into this.
EDIT 3
So this is the result of the $('element').data(), but I can't understand what it's trying to say, does this mean there are two binds to it. If so how do I find out what these binds are and why do they both not fire when the event is fired.
alt text http://archive.ilmv.co.uk/images/firebug-jquery-data-events.png
EDIT 4
Here's another screenshot of the problem, this time in a different place in the system. The green arrow is the element thats triggers the three ajax requests, not in firebug how there's six, and that they pair up and share timestamps down to the millisecond?
The top three are the ones that have not completed, the bottom three have return the correct result.
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v2.png
EDIT 5
The image below demonstrates what happens when a select box is changed, it fires three different ajax requests.
I've managed to do a bit more debugging and I can tell you the following:
The problem occurs regardless of how many ajax requests the initial element calls
The problem occurs regardless of what plugins are used
This event is definitely only being fired once
My uz_ajax wrapper function is only being fired once per target (see the firebug console, "Line 29: uz_ajax()".
I've added console.info on each of the jquery $.ajax() callbacks to see what's firing and when, notice how the only callback to fire is beforeSend().
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v3.png
EDIT 6
Right then, after #redsquare suggested via Twitter about using console.trace() to find out "where the second event is firing from" is, like I've always maintained I'm sure there isn't two events firing so I put the trace in the $.ajax() method, here's what happened:
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v4.png
As you can see I get the duplicate ajax request problem even though the $.ajax() method has only fired once, again the timestamps are identical. Have I come across a bug with jQuery?
EDIT 7
It happens on StackOverflow too!
alt text http://archive.ilmv.co.uk/images/jquery-duplicate-ajax-request-v5.png
Have you tried using a .click() instead? I have had issues with irregular activity using .change() in javascript. Give that a try.
Right, so I've come to a conclusion, I'm pretty sure that my problem is an issue with Firebug, as I've tested it the app on FF without Firebug turned on and it works as it should do.
This isn't the first time something JavaScript related has led me on a merry dance when the symptoms thrown by the problem don't offer any reasonable hint to the solution, but there we have it.
Massive thanks to #redsquare, who's helped massively both here, but via twitter and the jQuery IRC channel, many thanks dude!
Try to add return false to your onchange function.
This will stop jQuery from bubbling the event.
You should make sure that $("#my_select","#context").change(function(){ is only called once.
I have tried this:
$(selector).unbind().on(eventname,function(){
$.ajax({
//ajax code here
});
});
It worked.