Im trying to do my first debug ever. The scenario is that there is a notification dropdown in the header, the dropdown opens but does not close on only one on the pages and works fine everywhere else in the app.The problem is that on one of the pages, the dropdown opens but doesn't close, my guess is the jquery to close down the button does not work. And I get the message:
Uncaught TypeError: Cannot read property 'el' of undefined.
When I put a breakpoint and call stacktrace above the line which has the error, for both working and not working pages, I compare the trace. I see, that if you take notice on the Call Stack on the right for the first image (which is the one that works), the last Call Stack is jQuery.event.add.elemData.handle and the one not working has just elemData.handle.
Not working page:
Working page:
relevant functions from the Call Stack:
class: notification_dropdown_view.js
app.views.NotificationDropdown = app.views.Base.extend({
events: {
"click #notifications-link": "toggleDropdown"
},
initialize: function(){
$(document.body).click($.proxy(this.hideDropdown, this));
this.notifications = [];
this.perPage = 5;
this.hasMoreNotifs = true;
this.badge = this.$el;
this.dropdown = $("#notification-dropdown");
this.dropdownNotifications = this.dropdown.find(".notifications");
this.ajaxLoader = this.dropdown.find(".ajax_loader");
this.perfectScrollbarInitialized = false;
},
....
etc etc
....
hideDropdown: function(evt){
var inDropdown = $(evt.target).parents().is($(".dropdown-menu", this.dropdown));
var inHovercard = $.contains(app.hovercard.el, evt.target);
if(!inDropdown && !inHovercard && this.dropdownShowing()){
this.dropdown.removeClass("dropdown-open");
this.destroyScrollbar();
}
}
toggleDropdown: function(evt){
evt.stopPropagation();
if (!$("#notifications-link .entypo-bell:visible").length) { return true; }
evt.preventDefault();
if(this.dropdownShowing()){ this.hideDropdown(evt); }
else{ this.showDropdown(); }
},
class: app.js:
setupGlobalViews: function() {
app.hovercard = new app.views.Hovercard();
$('.aspect_membership_dropdown').each(function(){
new app.views.AspectMembership({el: this});
});
app.sidebar = new app.views.Sidebar();
},
The two things that I always go to when dealing with dynamic states of elements that depend strictly on user interaction is the JavaScript setInterval() method or the jQuery on.('propertychange click input');
Related
I have a problem where i am trying to disable certain forms fields which use the SelectStatic Widget based on a tick box, i have included the javascript below.
const vlan = document.querySelector('#id_vlan');
const physical_facing = document.querySelector('#id_physical_facing');
const service_type = document.querySelector('#id_service_type');
const bd_function = document.querySelector('#id_function');
function vlan_enable(){
vlan.disabled = false;
};
function vlan_disable(){
vlan.disabled = true;
};
function service_function_enable() {
service_type.disabled = false;
bd_function.disabled = false;
};
function service_function_disable() {
service_type.disabled = true;
bd_function.disabled = true;
};
(function() {
service_function_enable();
vlan_enable();
if(physical_facing.checked){
service_function_disable();
} else {
vlan_disable();
}
})();
function pf_event() {
if(physical_facing.checked) {
vlan_enable();
service_function_disable();
} else {
vlan_disable();
service_function_enable();
}
};
physical_facing.addEventListener('change', pf_event)
When on the Page, the VLAN field is a DynamicModelFormField and will never disable, but when toggling the switch on and off the fields do not re-enable, i know the event is getting fired because i can see it in the developer tools, the disabled tag gets applied and removed with no change on the page, This may be a simple mistake but would like if someone can point me in the right direction.
below is what the page looks like
Netbox Page
Has anybody had any success doing this with the new version of netbox as it worked fine in V2 with the SelectStatic2 widget.
I have integrated 'Embed Layout' comet chat on my site. Now I want to open particular friend chat on page load.
In the documentation, I've found below code to do the same. REF : Documentation Link
jqcc.cometchat.chatWith(user_id)
I have included in custom js from admin panel. However, it is showing below error in console
jqcc.cometchat.chatWith is not a function
But If I use same after friends list loaded from the console it is working fine.
How can I fix this issue?
Currently for time being I have fixed this issue by adding below code in custom js
var first_chat_loaded = false;
var first_chat = setInterval(function () {
try {
if (first_chat_loaded === false) {
// Function to get other user id defined in parent html page
var other_userid = parent.get_other_user_id();
jqcc.cometchat.chatWith(other_userid);
first_chat_loaded = true;
clear_first_load();
}
} catch (e) {
}
}, 1000);
function clear_first_load() {
clearInterval(first_chat);
}
Please let me know, If there is any proper way to do the same.
Kindly make use of this code snippet for the above mentioned issue
var checkfn = setInterval(
function(){
if(typeof jqcc.cometchat.chatWith == 'function'){
jqcc.cometchat.chatWith(user_id);
clearInterval(checkfn);
}
},
500);
I've been messing around with YouTube API to make a button that copies the video ID on click using jQuery. I have no idea why, I don't get any Javascript errors and after hours (actually been working on this problem for 2 days), I still haven't figured out why does the eventListener doesn't fire.
The eventListener is bound at the end of the function, which is fired when you hit a search button. Each time you click on the search button or on the next page/ previous page buttons, they fire the makeRequest function. Somehow, though, the function triggered by the eventListener never fires (the function code isn't in this parcel of code itself, but it's actually just console.log's). Can anyone help? Would be really appreciated <3
function makeRequest(e) {
$('#search-container')[0].innerHTML = '';
ytSearchResults = [];
var q = $('#query').val();
var request = gapi.client.youtube.search.list({
q: q,
part: 'snippet',
maxResults: 15,
pageToken: ytPage,
type: 'video',
safeSearch: 'none',
videoSyndicated: 'true'
});
request.execute(function(response) {
var str = response.result;
ytNextPage = str.nextPageToken;
ytPrevPage = str.prevPageToken;
for(i=0;i<str.items.length;i++){
$('#search-container')[0].innerHTML += '<br><image src='+str.items[i].snippet.thumbnails.default.url+'></image><br><button id="'+str.items[i].id.videoId+'" class="NCScopiable">'+str.items[i].snippet.title+'</button>';
ytSearchResults.push(str.items[i].id.videoId);
}
$('#search-container')[0].innerHTML += '<br><div id="button-changePage"><span id="button-prevPage" style="color:blue;cursor:pointer;margin:5px"><u>Previous Page</u></span><span id="button-nextPage" style="color:blue;cursor:pointer;margin:5px"><u>Next Page</u></span>';
if(e&&ytCurPage>0){
$('#button-prevPage')[0].style.display = 'block';
$('#button-nextPage')[0].style.display = 'block';
} else {
ytCurPage = 0;
$('#button-prevPage')[0].style.display = 'none';
}
$('#button-prevPage').on('click',function(){ytCurPage-=1;ytPage=ytPrevPage;makeRequest(true);});
$('#button-nextPage').on('click',function(){ytCurPage+=1;ytPage=ytNextPage;makeRequest(true);});
console.log('Current ytCurPage value: '+ytCurPage);
});
$('.NCScopiable').on('click',cTWI);
}
The problem is that the line
$('.NCScopiable').on('click',cTWI);
Is being executed before the code inside the callback passed to request.execute has fired, so those elements don't exist yet. Thus $('.NCScopiable') is returning nothing.
Move that line into the last line of your callback code and you should be good to go, for example:
request.execute(function(response) {
var str = response.result;
ytNextPage = str.nextPageToken;
ytPrevPage = str.prevPageToken;
// ...code removed for brevity...
// this was the code that is actually creating the elements with
// the NCScopiable class
console.log('Current ytCurPage value: '+ytCurPage);
$('.NCScopiable').on('click',cTWI);
});
I've created a Backbone, Marionette and Require.js application and am now trying to add smooth transitioning between regions.
To do this easily* ive decided to extend the marionette code so it works across all my pages (theres a lot of pages so doing it manually would be too much)
Im extending the marionette.region open and close function. Problem is that it now doesnt call the onClose function inside each of my views.
If I add the code directly to the marionette file it works fine. So I'm probably merging the functions incorrectly, right?
Here is my code:
extendMarrionette: function () {
_.extend(Marionette.Region.prototype, {
open : function (view) {
var that = this;
// if this is the main content and should transition
if (this.$el.attr("id") === "wrapper" && document.wrapperIsHidden === true) {
this.$el.empty().append(view.el);
$(document).trigger("WrapperContentChanged")
} else if (this.$el.attr("id") === "wrapper" && document.wrapperIsHidden === false) {
$(document).on("WrapperIsHidden:open", function () {
//swap content
that.$el.empty().append(view.el);
//tell router to transition in
$(document).trigger("WrapperContentChanged");
//remove this event listener
$(document).off("WrapperIsHidden:open", that);
});
} else {
this.$el.empty().append(view.el);
}
},
//A new function Ive added - was originally inside the close function below. Now the close function calls this function.
kill : function (that) {
var view = this.currentView;
$(document).off("WrapperIsHidden:close", that)
if (!view || view.isClosed) {
return;
}
// call 'close' or 'remove', depending on which is found
if (view.close) {
view.close();
}
else if (view.remove) {
view.remove();
}
Marionette.triggerMethod.call(that, "close", view);
delete this.currentView;
},
// Close the current view, if there is one. If there is no
// current view, it does nothing and returns immediately.
close : function () {
var view = this.currentView;
var that = this;
if (!view || view.isClosed) {
return;
}
if (this.$el.attr("id") === "wrapper" && document.wrapperIsHidden === true) {
this.kill(this);
} else if (this.$el.attr("id") === "wrapper" && document.wrapperIsHidden === false) {
//Browser bug fix - needs set time out
setTimeout(function () {
$(document).on("WrapperIsHidden:close", that.kill(that));
}, 10)
} else {
this.kill(this);
}
}
});
}
Why don't you extend the Marionette.Region? That way you can choose between using your custom Region class, or the original one if you don't need the smooth transition in all cases. (And you can always extend it again if you need some specific behavior for some specific case).
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#region-class
var MyRegion = Marionette.Region.extend({
open: function() {
//Your open function
}
kill: function() {
//Your kill function
}
close: function() {
//Your close function
}
});
App.addRegions({
navigationRegion: MyRegion
});
Perhaps your issue is that you are not passing a function to your event listener, but instead calling the code directly in the code below.
setTimeout(function(){
$(document).on("WrapperIsHidden:close", that.kill(that));
}, 10)
It is likely that you want something like this:
setTimeout(function(){
$(document).on("WrapperIsHidden:close", function (){ that.kill(that); });
}, 10)
Another possible problem is that you are mixing up your references to this/that in your kill function. It seems like you probably want var view to either be assigned to that.view or to use this rather than that throughout the method.
Answer to your additional problems:
You should try passing the view variable from the close function directly into your kill function because the reference to currentView is already changed to the new view object when you actually want to old view object. The reason this is happening is that you are setting a timeout before executing the kill function. You can see this if you look at the show source code. It expects close, open and then currentView assignment to happen synchronously in order.
I am building a django site and have implemented the redips.drag library in one of my pages to allow dragging of table rows. I want a very simple functionality in my code- add a listener, so when the row is dropped, it send the row data to the server. jQuery-speaking, something like this:
$(function() {
$(someDomElement).on('DropEvent', function() {
// send data to server
};
});
The problem though, is that redips.drag is not a jQuery plugin but a javascript one, so my knowledge is a little (more than a little) lacking. I can probably find some other library, but it's performing really well and I prefer understanding how to work with it than look for a different one.
I can probably handle the "sending the data to the server" part by myself, what I can't understand at all is how to "catch" the drop event, what part of the dom do I listen to? I tried adding monitorEvents to different selectors but failed completely.
I also tried to manipulate the script.js file (the one that initializes the row handling), but also failed. here's the one I'm using (example 20 in the redips package):
"use strict";
// define redips object container
var redips = {};
redips.init = function () {
// reference to the REDIPS.drag library and message line
var rd = REDIPS.drag,
msg = document.getElementById('msg');
// initialization
rd.init();
//
// ... more irrelevent code ...
//
// row event handlers
//
// row clicked (display message and set hover color for "row" mode)
rd.event.rowClicked = function () {
msg.innerHTML = 'Clicked';
};
// row row_dropped
rd.event.rowDropped = function () {
msg.innerHTML = 'Dropped';
};
// and so on...
};
// function sets drop_option parameter defined at the top
redips.setRowMode = function (radioButton) {
REDIPS.drag.rowDropMode = radioButton.value;
};
// add onload event listener
if (window.addEventListener) {
window.addEventListener('load', redips.init, false);
}
else if (window.attachEvent) {
window.attachEvent('onload', redips.init);
}
Now I tried adding a console.log('hello') to the rd.event.rowDropped function (right above the msg.innerHTML line), but that doesn't work, I drop the row and nothing shows in the log. Doing a console.log outside the init function works so I know the script can pass stuff to the console.
Please, can anyone help me? I'm at a complete loss...
I know this may be a little lateto answer your question but I found the answer. You need to use the event dropped and the attribute rd.obj (REDIPS.drag.obj) to get the id use it with simple javascript like getAttribute('id')
redips.init = function () {
// reference to the REDIPS.drag library and message line
var rd = REDIPS.drag,
msg = document.getElementById('msg');
// initialization
rd.init();
// row clicked (display message and set hover color for "row" mode)
rd.event.clicked = function () {
msg.innerHTML = 'Clicked' + rd.obj.getAttribute('id');
};
// row row_dropped
rd.event.dropped = function () {
msg.innerHTML = 'Dropped' + rd.obj.getAttribute('id');
};
};