emptying an array upon closing a dialog with Javascript and AngularJS - javascript

I'm using AngularJS. The following code sits in a controller. I'm trying to fill $scope.highlighted with Objects whose highlight property is set to true. I need $scope.highlighted to be emptied when the dialog is closed. For some reason, the $scope.highlighted in my closeDialog() function is not the same array I propagate in getHighlighted(). I can't tell if this is a AngularJS scope problem, a JavaScript reference issue, or something else?
$scope.highlighted = [];
$scope.closeDialog = function () {
console.log("closeDialog");
// Hide the dialog
$('#shared-list .modal').modal('hide');
// Clean up data for next shared list
console.log($scope.highlighted);
while ($scope.highlighted.length > 0) {
console.log("pop");
$scope.highlighted.pop();
}
console.log($scope.highlighted);
};
$scope.getHighlighted = function (root) {
var x, y;
for (x in root.CurrentItems) {
console.log(root.CurrentItems[x].ItemLabel + ": " + root.CurrentItems[x].highlight);
if (root.CurrentItems[x].highlight == true) {
console.log("push");
$scope.highlighted.push(root.CurrentItems[x]);
}
}
for (y in root.Folders) {
console.log(root.Folders[y].FolderLabel + ": " + root.Folders[y].highlight);
if (root.Folders[y].highlight == true) {
console.log("push");
$scope.highlighted.push(root.Folders[y]);
}
$scope.getHighlighted(root.Folders[y]);
}
};
$scope.showCreateSharedList = function () {
console.log("showShared");
console.log($scope.highlighted);
$scope.getHighlighted($scope.favorites);
console.log($scope.highlighted);
if ($scope.highlighted.length == 0) {
alert("Please select one or more items and/or folders to share.");
}
else {
$("#shared-list .modal").modal();
}
};

Related

How to access links within repeat control via CSJS in XPages?

In my application I display a link in a repeat control. This link will open a dialog control which displays details for a chosen row in the repeat.
Now I want to make the links appear as "read" when they are clicked.
I have defined the following function that will register the link ID clicked in a cookie and change the CSS color property of the link.
I can store the link ID in a cookie but when I try to find it in the DOM and change the CSS I fail. What am I doing wrong?
// onclick
function saveId(id) {
if ($.cookie('idCookie')) {
$.cookie('idCookie', $.cookie('idCookie') + "," + id);
} else {
$.cookie('idCookie', id);
}
}
// make all links colored
function setVisited() {
if (null != $.cookie('idCookie')) {
var idArray = $.cookie('idCookie').split(',');
console.log("#ids:" + idArray.length);
for (var x = 0; x < idArray.length; x++) {
console.log("ID: " + x + "=" + idArray[x]);
if ($('#' + idArray[x]).length) {
//link exists
$('#' + idArray[x]).css('color', 'red');
}
}
}
// assign saveId()
$(document).ready(function() {
$('a').click(function() {
saveId($(this).attr('id'));
});
setVisited();
});
The problem is that you cannot use the : in your selector as described here:
How to get the element id in repeat control
so your code must look something like this:
// onclick
function saveId(id) {
if ($.cookie('idCookie')) {
$.cookie('idCookie', $.cookie('idCookie') + "," + id);
} else {
$.cookie('idCookie', id);
}
}
// make all links colored
function setVisited() {
if (null != $.cookie('idCookie')) {
var idArray = $.cookie('idCookie').split(',');
for (var x = 0; x < idArray.length; x++) {
var link = $(document.getElementById(idArray[x])).get();
if (link.length) {
$(link).css('color', 'red');
}
}
}
}
// assign saveId()
$(document).ready(function() {
$('a').click(function() {
saveId($(this).attr('id'));
});
setVisited();
});
good luck!
You probably need to use the x$ jQuery selector as your ids contains colons: https://openntf.org/XSnippets.nsf/snippet.xsp?id=x-jquery-selector-for-xpages.

Handler defined with document.on deleted when object deleted from DOM

I have some severe memory leaks on my SPA. I managed to localize where the leak is, but I can't fix it. I have a code like this :
$(document).on("click.widget", ".glyphicon-collapse-down", function (e) {
var contentElement = $(e.target).closest(".widget").find(".widget-body");
$(e.target)
.removeClass("glyphicon-collapse-down")
.addClass("glyphicon-collapse-up");
kendo.fx(contentElement).expand("vertical").stop().play();
});
I can generate widgets over time on my single page, so I need the buttons to have a handler even if they don't exist yet (every widget come with a button group). When I switch from the current page to another, I delete everything from the page and load a new page with an ajax request. And here is appears the memory leak. I suspect that it might lies in the fact that the handlers are not deleted properly.
EDIT : The leak becomes very smaller when I don't include this script in the app :
//expand the widget
$(document).on("click.widget", ".glyphicon-collapse-down", function (e) {
var contentElement = $(e.target).closest(".widget").find(".widget-body");
$(e.target)
.removeClass("glyphicon-collapse-down")
.addClass("glyphicon-collapse-up");
kendo.fx(contentElement).expand("vertical").stop().play();
});
//collapse the widget
$(document).on("click.widget", ".glyphicon-collapse-up", function (e) {
var contentElement = $(e.target).closest(".widget").find(".widget-body");
$(e.target)
.removeClass("glyphicon-collapse-up")
.addClass("glyphicon-collapse-down");
kendo.fx(contentElement).expand("vertical").stop().reverse();
});
//remove the widget and updating the layout accordingly
$(document).on("click.widget", ".glyphicon-remove", function (e) {
var contentElement = $(e.target).closest(".widget");
var ancestor = $(contentElement).parent();
var rightColumn = $("#right-column");
var mainColumn = $("#main-column");
kendo.unbind(contentElement);
kendo.destroy(contentElement);
$(contentElement).fadeOut().remove();
// //Widget layout modification on remove
if ((rightColumn.items().length - 1 == 0) && (ancestor.attr("id") == "right-column")) {
if (mainColumn.items().length == 1) {
$("#main-column").removeClass("col-lg-6").hide().addClass("col-lg-12").fadeIn();
}
else if (mainColumn.items().length > 1) {
var firstWidget = mainColumn.items().last();
$(firstWidget).hide().prependTo("#right-column").fadeIn();
}
}
if ((mainColumn.items().length - 1 == 0) && (ancestor.attr("id") == "main-column")) {
if (rightColumn.items().length == 1) {
$("#right-column").removeClass("col-lg-6").hide().addClass("col-lg-12").fadeIn();
}
else if (rightColumn.items().length > 1) {
var firstWidget = rightColumn.items().last();
$(firstWidget).hide().prependTo("#main-column").fadeIn();
}
}
});
//Enable the widget fullscreen
$(document).on("click.widget", ".widget-fullscreen-on", function (e) {
var contentElement = $(e.target).closest(".widget");
contentElement.addClass("fullscreen");
$(e.target)
.removeClass("glyphicon-resize-full")
.removeClass("widget-fullscreen-on")
.addClass("glyphicon-resize-small")
.addClass("widget-fullscreen-off");
});
//Disable the widget fullscreen
$(document).on("click.widget", ".widget-fullscreen-off", function (e) {
var contentElement = $(e.target).closest(".widget");
contentElement.removeClass("fullscreen");
$(e.target)
.removeClass("glyphicon-resize-small")
.removeClass("widget-fullscreen-off")
.addClass("glyphicon-resize-full")
.addClass("widget-fullscreen-on");
});
//Inserts a widget into the page content and modifies the layout accordingly
function insertWidget(jtext) {
jtext.attr("id", "");
if (($('#main-column').items().length == 0) && ($('#right-column').items().length == 0)) {
if ($("#main-column").hasClass("col-lg-12")) {
$(jtext).hide().prependTo('#main-column').fadeIn();
}
else if ($("#right-column").hasClass("col-lg-12")) {
$(jtext).hide().prependTo('#right-column').fadeIn();
}
}
else if ($("#main-column").hasClass("col-lg-12")) {
$("#main-column").removeClass("col-lg-12").addClass("col-lg-6");
$(jtext).hide().prependTo('#right-column').fadeIn();
}
else if ($("#right-column").hasClass("col-lg-12")) {
$("#right-column").removeClass("col-lg-12").addClass("col-lg-6");
$(jtext).hide().prependTo('#main-column').fadeIn();
}
else if ($('#right-column').items().length < $('#main-column').items().length) {
$(jtext).hide().prependTo('#right-column').fadeIn();
}
else {
$(jtext).hide().prependTo('#main-column').fadeIn();
}
}

I've added a "input" inside the jPushMenu, but if i "click" on the input the menu will close. I could I prevent this behaviour?

I'm trying to add a search form inside a jPushMenu
but everytime I click on the input text, the Menu will close (probably because of the "closeOnClickOutside" parameter
I'm trying to write a function like this:
$('.cbp-spmenu input').on('click',function() {
// dont execute jPushMenu.close(o);
});
but I really can't figure it out how to do this
This is the jPushMenu.js
/*!
* jPushMenu.js
* 1.1.1
* #author: takien
* http://takien.com
* Original version (pure JS) is created by Mary Lou http://tympanus.net/
*/
(function($) {
$.fn.jPushMenu = function(customOptions) {
var o = $.extend({}, $.fn.jPushMenu.defaultOptions, customOptions);
$('body').addClass(o.pushBodyClass);
// Add class to toggler
$(this).addClass('jPushMenuBtn');
$(this).click(function(e) {
e.stopPropagation();
var target = '',
push_direction = '';
// Determine menu and push direction
if ($(this).is('.' + o.showLeftClass)) {
target = '.cbp-spmenu-left';
push_direction = 'toright';
}
else if ($(this).is('.' + o.showRightClass)) {
target = '.cbp-spmenu-right';
push_direction = 'toleft';
}
else if ($(this).is('.' + o.showTopClass)) {
target = '.cbp-spmenu-top';
}
else if ($(this).is('.' + o.showBottomClass)) {
target = '.cbp-spmenu-bottom';
}
if (target == '') {
return;
}
$(this).toggleClass(o.activeClass);
$(target).toggleClass(o.menuOpenClass);
if ($(this).is('.' + o.pushBodyClass) && push_direction != '') {
$('body').toggleClass(o.pushBodyClass + '-' + push_direction);
}
// Disable all other buttons
$('.jPushMenuBtn').not($(this)).toggleClass('disabled');
return;
});
var jPushMenu = {
close: function (o) {
$('.jPushMenuBtn,body,.cbp-spmenu')
.removeClass('disabled ' + o.activeClass + ' ' + o.menuOpenClass + ' ' + o.pushBodyClass + '-toleft ' + o.pushBodyClass + '-toright');
}
// Close menu on clicking outside menu
if (o.closeOnClickOutside) {
$(document).click(function() {
jPushMenu.close(o);
});
}
// Close menu on clicking menu link
if (o.closeOnClickLink) {
$('.cbp-spmenu a').on('click',function() {
if ( $(this).hasClass('preventclick') ) return;
jPushMenu.close(o);
});
}
// Close menu on clicking menu link
if (o.closeOnFocus) {
$('.logo_wrapper a').on('focus',function() {
jPushMenu.close(o);
});
}
};
/*
* In case you want to customize class name,
* do not directly edit here, use function parameter when call jPushMenu.
*/
$.fn.jPushMenu.defaultOptions = {
pushBodyClass : 'push-body',
showLeftClass : 'menu-left',
showRightClass : 'menu-right',
showTopClass : 'menu-top',
showBottomClass : 'menu-bottom',
activeClass : 'menu-active',
menuOpenClass : 'menu-open',
closeOnClickOutside: true,
closeOnClickLink : true,
closeOnFocus : true
};
})(jQuery);
This is caused by $(document).click() on line 66 in file jPushMenu.js (here). You can fix this by modifying your local file as follows:
// Close menu on clicking outside menu
if (o.closeOnClickOutside) {
$(document).click(function(e) {
if (!$(e.target).closest('.cbp-spmenu').length && $('.cbp-spmenu').is('.' + o.menuOpenClass)) {
jPushMenu.close(o)
}
});
}
And initialize your menu using closeOnClickLink as:
$('#menu').jPushMenu({
closeOnClickLink: false
})
I might send a pull request for this :)

how to make the jquery function load before one ajax function finish

How do I fire one event before the previous function completed its function?
I have the following AJAX code :
var BrainyFilter = {
//...
init: function (opts) {},
changeTotalNumbers: function (data) {
jQuery(BrainyFilter.filterFormId).find('.bf-count').remove();
jQuery(BrainyFilter.filterFormId).find('option span').remove();
jQuery(BrainyFilter.filterFormId).find('select').removeAttr('disabled');
jQuery('.bf-attr-filter').not('#bf-price-container').find('input, option')
.attr('disabled', 'disabled')
.parents('.bf-attr-filter')
.addClass('bf-disabled');
if (data && data.length) {
for (var i = 0; i < data.length; i++) {
jQuery('.bf-attr-' + data[i].id + ' .bf-attr-val').each(function (ii, v) {
if (jQuery(v).text() == data[i].val) {
var parent = jQuery(v).parents('.bf-attr-filter').eq(0);
var isOption = jQuery(v).prop('tagName') == 'OPTION';
var selected = false;
if (isOption) {
jQuery(v).removeAttr('disabled');
selected = jQuery(v)[0].selected;
} else {
parent.find('input').removeAttr('disabled');
selected = parent.find('input')[0].checked;
}
parent.removeClass('bf-disabled');
if (!selected) {
if (!isOption) {
parent.find('.bf-cell').last().append('<span class="bf-count">' + data[i].c + '</span>');
} else {
jQuery(v).append('<span> (' + data[i].c + ')</span>');
}
}
}
});
}
jQuery('.bf-attr-filter input[type=checkbox]').filter(':checked')
.parents('.bf-attr-block').find('.bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text();
jQuery(v).text(t);
});
// since opencart standard filters use logical OR, all the filter groups
// should have '+' if any filter was selected
if (jQuery('.bf-opencart-filters input[type=checkbox]:checked').size()) {
jQuery('.bf-opencart-filters .bf-count').each(function (i, v) {
var t = '+' + jQuery(v).text().replace('+', '');
jQuery(v).text(t);
});
}
}
// disable select box if it hasn't any active option
jQuery(BrainyFilter.filterFormId).find('select').each(function (i, v) {
if (jQuery(v).find('option').not('.bf-default,[disabled]').size() == 0) {
jQuery(v).attr('disabled', 'true');
}
});
},
//...
} // close the BrainyFilter
I also have another jQuery file running to get the bf-count value using $('.bf-count').text().
When the page load, the bf-count value is empty. Since the code above inject the bf-count, I will need to wait until it finishes the for loop in order to get the bf-count value.
What is the best way to approach this?
without knowing how the second js file is loaded, I can only give you a guesstimate suggestion.
If you want to run the second js file code after the page is fully loaded, you can wrap the code in:
jQuery(window).load(function(){
//your code here. runs after the page is fully loaded
});
jQuery documentation: http://api.jquery.com/load-event/
"The load event is sent to an element when it and all sub-elements have been completely loaded. This event can be sent to any element associated with a URL: images, scripts, frames, iframes, and the window object."

Executing a function after the dgrid renderRow

I'm trying to tie a function to be executed after the renderRow event of the grid. So I used the aspect.after from DOJO, but here is the kicker. This execute before the row is indeed rendered, therefore the divs\tds are not on the screen yet. And since I do want to use the position of the items, using the dojo/domgeometry returns an object filled with zeroes. How can I guarantee that my function will execute after the row is finished displaying?
Below you can find the JS where I'm calling it.
aspect.after(grid, 'renderRow', function(row, args) {
var object = args[0];
if (object.type == 'tipo_exec') {
row.className += ' black';
} else if(object.type == 'exec') {
row.className += ' gray';
} else if(object.type == 'ic') {
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(row));
}
);
}
}
return row;
});
EDIT: Another thing, I'm using the tree extension, and the renderRow happens after a click on the parent to expand.
EDIT: So here is a bit of more info in case it is needed. The store is simple:
store = new Observable(new Memory({'data': data,
'getChildren': function(parent, options){
return this.query({'parent': parent.id}, options);
},
'mayHaveChildren': function(parent){
return parent.hasChildren;
}
}));
And the grid is declared as:
grid = new (declare([OnDemandGrid, Selection, Keyboard, CompoundColumns]))({
'columns': nCols,
'query': { 'parent': undefined },
'store': store
}, gridId);
This is the inside of the aspect after
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
console.log('just before adding the refresh');
on.once(this, 'dgrid-refresh-complete', function(){
console.log('finished refreshing');
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(node));
}
);
});
}
The console.log('finished refreshing');never gets called, neither does the the position log.
There are many columns on the grid, a couple tied on a compouding column, a name colum which is a tree, and a couple of others. The renderRow is called when expanding the tree!
Image of the grid with a couple of data removed
You can defer the invocation of domGeom.position(row) until the dgrid-refresh-complete event has been emitted. You'll need to include dojo/on.
aspect.after(grid, 'renderRow', function(row, args) {
var object = args[0];
if (object.type == 'tipo_exec') {
row.className += ' black';
} else if(object.type == 'exec') {
row.className += ' gray';
} else if(object.type == 'ic') {
if ((typeof(object.dep)!='undefined') && (object.dep.length > 0)) {
on.once(this, 'dgrid-refresh-complete', function(){
require(['dojo/dom-geometry','dojo/dom-construct'],
function(domGeom, domConstruct){
console.log(domGeom.position(row));
}
);
})
}
}
return row;
});
EDIT
Updated jsfiddle to accommodate tree
http://jsfiddle.net/rayotte/q8bCx/2/

Categories

Resources