.bind() statement not working in jQuery Easy Confirmation plugin - jquery-plugins

Did anyone who used jQuery Easy Confirmation plugin run into this issue - the button upon which the confirm box is bound loses its original click event after the first click? I had to change the plugin code to this to make it work. The difference here is between .bind and .click. Can anyone explain why? Pls. let me know if my question is not clear. Thx!
Original plugin code:
// Re-bind old events
var rebindHandlers = function () {
if (target._handlers != undefined) {
jQuery.each(target._handlers, function () {
//this is the difference
$target.bind(type, this);
});
}
}
Changed (working) code:
// Re-bind old events
var rebindHandlers = function () {
if (target._handlers != undefined) {
jQuery.each(target._handlers, function () {
//this is the difference
if(type == 'click')
$target.click(this);
else {
$target.bind(type, this);
}
});
}
}

Try using some alerts to see what's happening...
// Re-bind old events
var rebindHandlers = function () {
if (target._handlers != undefined) {
jQuery.each(target._handlers, function () {
if(type == 'click')
alert('$target.click(' + this + ');');
//$target.click(this);
else {
alert('$target.bind(' + type + ', ' + this + ');');
//$target.bind(type, this);
}
});
}
}

Related

failing to reset language selection after sync

I am facing a problem which I am not aware how to resolve. Let me describe elaborately below:
I have a commonViewModel kendo class where event like save, cancel are written. I am facing problem with the save event of this class.
save: function () {
var that = this;
var routeLanguage = "";
that._showBackConfirmation(false);
that.set("isFormSubmitted", true);
console.log("form is valid, sending the save request!");
if (vm.get("languageTabsVm.selectedLanguage")) {
routeLanguage = "/" + vm.get("languageTabsVm.selectedLanguage");
}
else if (that.get("model.Languages") && that.get("model.Languages").length > 1) {
that.get("model.Languages").forEach(function (lang) {
if (lang.get("IsActive") === true) {
//sätt cv-visning till det språk jag senast redigerade på detta item
routeLanguage = "/" + lang.LanguageId;
}
});
}
//if i call the function _loadDefaultLanguageSelection here, it
// works. because, the datasource is not synced yet.
//Make sure the datasource are syncing changes to the server (includes all crud)
return that.dataSource.sync().fail(function (e) {
//i need to do something here to be in the same language tab. But
//as i am changing directly in to model, it is not possible. But
//saving directly to model is essential because that model is
//shared to other viewmodel for language tab synching purpose.
that.set("isFormSubmitted", false);
console.log("form rejected");
}).done(function () {
if (that.get("isPersonaldetail")) {
var name = that.get("model.Name");
if (name.length > 12)
name = name.substring(0, 11) + "...";
$("#profileName").text(name);
}
that.set("isFormSubmitted", false);
that.set("isSelected", false);
// it is called from here right now. but it is failing because
// model is updated but not synced in that function
that._loadDefaultLanguageSelection();
router.navigate(that.nextRoute + routeLanguage);
});
},
_loadDefaultLanguageSelection: function () {
var that = this;
if (that.get("model.Languages") && that.get("model.Languages").length > 1) {
that.get("model.Languages").forEach(function (lang) {
if (!that.get("isPersonaldetail")) {
lang.set("IsActive", lang.get("LanguageId") === vm.get("languageTabsVm.selectedLanguage"));
}
});
}
},
So, my question is, how can i resolve this problem. one solution is i will have to sync twice. that is not nice. So, I am looking for efficient solution.

How can I check until an element is clickable using nightwatchjs?

How can I check until an element is clickable using nightwatch js? I want to click on an element but when I run nightwatch, selenium does not click on the element because it is not clickable yet.
Something like this should work. Let me know if you have questions
var util = require('util');
var events = require('events');
/*
* This custom command allows us to locate an HTML element on the page and then wait until the element is both visible
* and does not have a "disabled" state. It rechecks the element state every 500ms until either it evaluates to true or
* it reaches maxTimeInMilliseconds (which fails the test). Nightwatch uses the Node.js EventEmitter pattern to handle
* asynchronous code so this command is also an EventEmitter.
*/
function WaitUntilElementIsClickable() {
events.EventEmitter.call(this);
this.startTimeInMilliseconds = null;
}
util.inherits(WaitUntilElementIsClickable, events.EventEmitter);
WaitUntilElementIsClickable.prototype.command = function (element, timeoutInMilliseconds) {
this.startTimeInMilliseconds = new Date().getTime();
var self = this;
var message;
if (typeof timeoutInMilliseconds !== 'number') {
timeoutInMilliseconds = this.api.globals.waitForConditionTimeout;
}
this.check(element, function (result, loadedTimeInMilliseconds) {
if (result) {
message = '#' + element + ' was clickable after ' + (loadedTimeInMilliseconds - self.startTimeInMilliseconds) + ' ms.';
} else {
message = '#' + element + ' was still not clickable after ' + timeoutInMilliseconds + ' ms.';
}
self.client.assertion(result, 'not visible or disabled', 'visible and not disabled', message, true);
self.emit('complete');
}, timeoutInMilliseconds);
return this;
};
WaitUntilElementIsClickable.prototype.check = function (element, callback, maxTimeInMilliseconds) {
var self = this;
var promises =[];
promises.push(new Promise(function(resolve) {
self.api.isVisible(element, function(result) {
resolve(result.status === 0 && result.value === true);
});
}));
promises.push(new Promise(function(resolve) {
self.api.getAttribute(element, 'disabled', function (result) {
resolve(result.status === 0 && result.value === null);
});
}));
Promise.all(promises)
.then(function(results) {
var now = new Date().getTime();
const visibleAndNotDisabled = !!results[0] && !!results[1];
if (visibleAndNotDisabled) {
callback(true, now);
} else if (now - self.startTimeInMilliseconds < maxTimeInMilliseconds) {
setTimeout(function () {
self.check(element, callback, maxTimeInMilliseconds);
}, 500);
} else {
callback(false);
}
})
.catch(function(error) {
setTimeout(function () {
self.check(element, callback, maxTimeInMilliseconds);
}, 500);
});
};
module.exports = WaitUntilElementIsClickable;
Add this code as a file to your commands folder. It should be called waitUntilElementIsClickable.js or whatever you want your command to be.
Usage is:
browser.waitUntilElementIsClickable('.some.css');
You can also use page elements:
var page = browser.page.somePage();
page.waitUntilElementIsClickable('#someElement');
You can use waitForElementVisible() combined with the :enabled CSS pseudo-class.
For example, the following will wait up to 10 seconds for #element to become enabled, then click it (note that the test will fail if the element doesn't become enabled after 10 seconds):
browser
.waitForElementVisible('#element:enabled', 10000)
.click('#element');
Can you show an example element,usually there should be an attribute name "disabled" if the button is not clickable, this should work.
browser.assert.attributeEquals(yourCSS, 'disabled', true)
I'm unable to comment but there are a couple of issues with the code suggested by Alex R.
First, the code will not work with Firefox as geckodriver does not return a 'status'. So this:
resolve(result.status === 0 && result.value === true)
needs to be changed to this:
resolve(result.value === true).
Second, the line:
self.client.assertion(result, 'not visible or disabled', 'visible and not disabled', message, true);
doesn't work and needs to be commented out in
order to get the code to run.

AngularJs 2 promises inside a watch the second one never works

I have 2 lists in my application and the user is supposed to drag and drop items from one list to another.
When the user drops an element from one of the lists to the other list a request has to be made to the server side code to update a field in the database (SelectedForDiscussion).
This is the code in my controller:
$scope.$watch("questionsDiscuss", function (value) {
var question = $.Enumerable.From($scope.questionsDiscuss).Where(function (item) { return !item.SelectedForDiscussion }).FirstOrDefault()
if (question != undefined) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, true)
.then(function (output) {
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) { return item.Id == output.data.questionId })
.FirstOrDefault();
var index = $.Enumerable.From($scope.questionsDiscuss).IndexOf(question);
if (question != undefined)
if (output.data.result != "success") {
$scope.questionsDiscuss.splice(index, 1);
$scope.questionsReceived.splice(0, 0, question);
}
else {
question.SelectedForDiscussion = true;
$scope.questionsDiscuss[index] = question;
}
});
}
else {
var question = $.Enumerable.From($scope.questionsReceived).Where(function (item) { return item.SelectedForDiscussion }).FirstOrDefault();
if (question != undefined) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, false)
.then(function (output) {
var question = $.Enumerable.From($scope.questionsReceived)
.Where(function (item) { return item.Id == output.data.questionId })
.FirstOrDefault();
var index = $.Enumerable.From($scope.questionsReceived).IndexOf(question);
if (question != undefined)
if (output.data.result != "success") {
$scope.questionsReceived.splice(index, 1);
$scope.questionsDiscuss.splice(0, 0, question);
}
else {
question.SelectedForDiscussion = false;
$scope.questionsReceived[index] = question;
}
});
}
}
}, true);
I have 4 javascript breakpoint placed at the following lines within Firebug:
2 of them at the following lines:
if (question != undefined) {
One at:
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
And the other at:
var question = $.Enumerable.From($scope.questionsReceived)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
The following happens:
The breakpoints at:
if (question != undefined) {
are always reached.
The breakpoint at
var question = $.Enumerable.From($scope.questionsDiscuss)
.Where(function (item) {
return item.Id == output.data.questionId
})
.FirstOrDefault();
is also reached.
The other is never reached.
Both responses are OK(response code 200).
Everything should work perfectly but the then clause in the second promise is never reached.
Can anyone tell me what I am doing wrong?
The serverside appplication is an ASP.NET MVC application written in C#.
Edit 1:
I figured out why this was happening and I have a work around for it. I am stil interested in an actual solution.
The problem is angularjs throws an error then swallows it when calling $http for the second time. The error is:
digest alredy in progress
I think this is because in my directive I have this code:
dndfunc = function (scope, element, attrs) {
// contains the args for this component
var args = attrs.dndBetweenList.split(',');
// contains the args for the target
var targetArgs = $('#' + args[1]).attr('dnd-between-list').split(',');
// variables used for dnd
var toUpdate;
var target;
var startIndex = -1;
// watch the model, so we always know what element
// is at a specific position
scope.$watch(args[0], function (value) {
toUpdate = value;
}, true);
// also watch for changes in the target list
scope.$watch(targetArgs[0], function (value) {
target = value;
}, true);
// use jquery to make the element sortable (dnd). This is called
// when the element is rendered
$(element[0]).sortable({
items: 'div',
start: function (event, ui) {
// on start we define where the item is dragged from
startIndex = ($(ui.item).index());
},
stop: function (event, ui) {
var newParent = ui.item[0].parentNode.id;
// on stop we determine the new index of the
// item and store it there
var newIndex = ($(ui.item).index());
var toMove = toUpdate[startIndex];
// we need to remove him from the configured model
toUpdate.splice(startIndex, 1);
if (newParent == args[1]) {
// and add it to the linked list
target.splice(newIndex, 0, toMove);
} else {
toUpdate.splice(newIndex, 0, toMove);
}
// we move items in the array, if we want
// to trigger an update in angular use $apply()
// since we're outside angulars lifecycle
scope.$apply(targetArgs[0]);
scope.$apply(args[0]);
},
connectWith: '#' + args[1]
})
}
And there are 2 calls to apply at the end which trigger a new digest cycle I think.
Anyway I fixed it by adding this call before the calls to apply:
if (scope.updateLists != undefined)
scope.updateLists();
And moved all the code from the watch into the updateLists function.
Also because people have mentioned the service as having something to do with it I am pasting the relevant code within it:
GetQuestionsReceived: function (eid, criteria, page, rows) {
var promise = this.GetQuestionsReceivedInternal(eid,criteria, page, rows).then(function (response) {
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
},
GetQuestionsReceivedInternal: function (eid, criteria, page, rows) {
return $http({ method: 'GET',
url: '../QuestionManagement/GetQuestions?eventId='+eid+'&page=1&rows=5&'+serialize(criteria)
}).
success(function (data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
results = data;
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
if (window.console && console.log) {
console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
}
});
},
GetQuestionsDiscuss: function (eid,criteria, page, rows) {
var promise = this.GetQuestionsDiscussInternal(eid,criteria, page, rows).then(function (response) {
// The return value gets picked up by the then in the controller.
return response;
});
// Return the promise to the controller
return promise;
},
GetQuestionsDiscussInternal: function (eid,criteria, page, rows) {
return $http({ method: 'GET',
url: '../QuestionManagement/GetQuestions?eventId=' + eid + '&page=1&rows=5&' + serialize(criteria)
}).
success(function (data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
response = data;
}).
error(function (data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
if (window.console && console.log) {
console.log("Could not obtain questions received. Error:" + data + "Status:" + status + "Headers:" + headers + "Config:" + config);
}
});
},
You have two very similar blocks of code, which could be generalized and placed in a function wrapper, leaving behind a very simple calling function.
If you can get everything into that form, then I think you will find it easier to debug.
Here is an attempt to do so :
function updateSelectionStatus(qA, qB, bool) {
var en = $.Enumerable.From(qA);
var question = en.Where(function (item) {
return bool ? !item.SelectedForDiscussion : item.SelectedForDiscussion;
}).FirstOrDefault();
if(question) {
questionSelectionService.UpdateQuestionSelectionStatus(question.Id, bool).then(function (output) {
if (output.data.result == "success") {
question.SelectedForDiscussion = bool;
}
else {
qA.splice(en.IndexOf(question), 1);
qB.unshift(question);
}
});
}
return question;
}
$scope.$watch("questionsDiscuss", function (value) {
if (!updateSelectionStatus($scope.questionsDiscuss, $scope.questionsReceived, true) {
updateSelectionStatus($scope.questionsReceived, $scope.questionsDiscuss, false);
}
}, true);
I may have made some false assumptions and simplified too much (eg. purging the inner $.Enumerable.From, which appears to reselect the same question as the outer), so you may well need to rework my code.
I'm advocating a principle here, rather than offering a solution.

How to Fix Poor Performance on Filter By Text

A while back I found some code that allows you to filter the contents of a SELECT by typing in a text element. It works well however, over time the performance degrades pretty badly. I'm not sure if it is the filter code or the way in which I am activating it.
The SELECT shows up in a modal dialog (bootstrap) so I have the following code:
$('#myModal').on('shown', function () {
$(".focusable").val("").focus();
var select = $('#myModal').find(".modal-body").find("select");
var text = $('#myModal').find(".modal-body").find("input[type='text']");
select.filterByText(text, true);
});
And here is the filter code:
jQuery.fn.filterByText = function (textbox, selectSingleMatch) {
return this.each(function () {
var select = this;
var options = [];
$(select).find('option').each(function () {
options.push({value:$(this).val(), text:$(this).text(), data:$(this).data("short-name")});
});
$(select).data('options', options);
$(textbox).bind('change keyup', function () {
var options = $(select).empty().data('options');
var search = $.trim($(this).val());
var regex = new RegExp(search, 'gi');
$.each(options, function (i) {
var option = options[i];
if (option.text.match(regex) !== null) {
var copyOption = $('<option>').text(option.text).val(option.value);
copyOption.data("short-name", option.data);
$(select).append(copyOption);
}
});
if (selectSingleMatch === true &&
$(select).children().length === 1) {
$(select).children().get(0).selected = true;
}
});
});
};
Can anyone shed some light on where my performance issue(s) might be and how to solve it?
reading through the comments I would suggest to add the following:
$(textbox).bind('change keyup', function(event) {
console.log(event);
// your code
});
Is the event triggered more than once on a single keyup after some times the dialog is shown?
$('#myModal').on('hidden', function () {
$('#myModal').find(".modal-body").find("input[type='text']").off("change keyup");
});

hidding elements in a layout page mvc3

ok so im having a hard time hiding some layout sections (divs in my layout page and im using mvc3).
I have this js fragment which is basically the main logic:
$('.contentExpand').bind('click', function () {
$.cookie('right_container_visible', "false");
});
//Cookies Functions========================================================
//Cookie for showing the right container
if ($.cookie('right_container_visible') === 'false') {
if ($('#RightContainer:visible')) {
$('#RightContainer').hide();
}
$.cookie('right_container_visible', null);
} else {
if ($('#RightContainer:hidden')) {
$('#RightContainer').show();
}
}
as you can see, im hidding the container whenever i click into some links that have a specific css. This seems to work fine for simple tests. But when i start testing it like
.contentExpand click --> detail button click --> .contentExpand click --> [here unexpected issue: the line $.cookie('right_container_visible', null); is read but it doesnt set the vaule to null as if its ignoring it]
Im trying to understand whats the right logic to implement this. Anyone knows how i can solve this?
The simpliest solution is to create variable outside delegate of bind.
For example:
var rightContVisibility = $.cookie('right_container_visible');
$('.contentExpand').bind('click', function () {
$.cookie('right_container_visible', "false");
rightContVisibility = "false";
});
if (rightContVisibility === 'false') {
...
}
The best thing that worked for me was to create an event that can catch the resize of an element. I got this from another post but I dont remember which one. Anyway here is the code for the event:
//Event to catch rezising============================================================================
(function () {
var interval;
jQuery.event.special.contentchange = {
setup: function () {
var self = this,
$this = $(this),
$originalContent = $this.text();
interval = setInterval(function () {
if ($originalContent != $this.text()) {
$originalContent = $this.text();
jQuery.event.handle.call(self, { type: 'contentchange' });
}
}, 100);
},
teardown: function () {
clearInterval(interval);
}
};
})();
//=========================================================================================
//Function to resize the right container============================================================
(function ($) {
$.fn.fixRightContainer = function () {
this.each(function () {
var width = $(this).width();
var parentWidth = $(this).offsetParent().width();
var percent = Math.round(100 * width / parentWidth);
if (percent > 62) {
$('#RightContainer').remove();
}
});
};
})(jQuery);
//===================================================================================================

Resources