How to call a script on success of $.ajax - javascript

The goal
Call a script (to be more specific, qTip2 script) on success of $.ajax function from jQuery.
The problem
I have the following script to work with KnockoutJS:
$.ajax({
url: "/ProductsSummary/List?output=json",
dataType: "json",
success: function (data) {
var mappingOptions = {
create: function (options) {
return (new (function () {
this.finalMeasure = ko.computed(function () {
return this.quantity() > 1 ? this.measure() + "s"
: this.measure();
}, this);
this.infoComposition = ko.computed(function () {
return this.quantity() + ' ' + this.finalMeasure();
}, this);
ko.mapping.fromJS(options.data, {}, this);
})());
}
};
ViewModel.Summary.products = ko.mapping.fromJS(data, mappingOptions);
ko.applyBindings(ViewModel);
$("ul.products-list li").each(function () {
var $productId = $(this).data("productid"),
$match = $(".summary")
.find("li[data-productid=" + $productId + "]")
.length > 0;
if ($match) {
$(this).find("button.action").addClass("remove");
} else {
$(this).find("button.action").addClass("add");
}
});
}
});
In the following fragment, I set a class to a button to define its style, but I have no success because I need to call the qTip2 again to render the new tooltip. See:
$("ul.products-list li").each(function () {
var $productId = $(this).data("productid"),
$match = $(".summary")
.find("li[data-productid=" + $productId + "]")
.length > 0;
if ($match) {
$(this).find("button.action").addClass("remove");
} else {
$(this).find("button.action").addClass("add");
}
});
To make the things work, I have to call the qTip2 script after this fragment, but it was previously called.
To do not be redundant or practice the DRY concept, how can I call, inside of the "on success", qTip2 script again?
A little of code
My qTip2 Script:
$(function () {
var targets = $("ul.products-list li .controls
button.action.add").attr('oldtitle', function () {
var title = $(this).attr('title');
return $(this).removeAttr('title'), title;
}),
shared_config = {
content: {
text: function (event, api) {
return $(event.currentTarget).attr('oldtitle');
}
},
position: {
viewport: $(window),
my: "bottom center",
at: "top center",
target: "event"
},
show: {
target: targets
},
hide: {
target: targets
},
style: "qtip-vincae qtip-vincae-green"
};
$('<div/>').qtip(shared_config);
$('<div/>').qtip($.extend(true, shared_config, {
content: {
text: function (event, api) {
var target = $(event.currentTarget),
content = target.data("tooltipcontent");
if (!content) {
content = target.next("div:hidden");
content && target.data("tooltipcontent", content);
}
return content || false;
}
},
position: {
my: "top center",
at: "bottom center",
viewport: $(".content"),
container: $(".content")
},
show: {
event: "click",
effect: function () {
$(this).show(0, function () {
$(this).find("input[name=productQuantity]").focus();
});
}
},
hide: {
event: "click unfocus",
fixed: false
},
events: {
hide: function (event, api) {
$($(this).find("input[type=text].quantity")).val("");
$($(this).find("button")).prop("disabled", true);
}
},
style: "qtip-vincae qtip-vincae-grey"
}));
});
Thanks in advance.

As I see it you should call simply $(this).find("button.action").qtip() or .qtip(...) and set/update what you want.
This demo could be your cheat-sheet:
http://craigsworks.com/projects/qtip2/demos/#validation

Related

Backbone subview is not rendered, "Uncaught ReferenceError: view is not defined" error returned

I am working on a site that uses Backbone.js, jQuery and I am trying to render a subview that has to display a description of the current page, loaded depending on a choice made from a dropdown menu. I searched for more info in the web but I am still stuck on this. Please help!
Here is the main view in which I have to load the description view:
const InquiryContentView = Backbone.View.extend(
{
el: $('#inquiryContent'),
events: {
'change #styles': 'renderTabs',
'click li.tab': 'renderTabPanel'
},
initialize: function () {
const view = this
this.inquiryContent = new InquiryContent
this.inquiryContent.fetch(
{
success: function () {
view.listenTo(view.inquiryContent, 'update', view.render)
view.render()
}
})
},
render: function () {
const data = []
this.inquiryContent.each(function (model) {
const value = {}
value.id = model.id
value.text = model.id
value.disabled = !model.get('active')
data.push(value)
})
data.unshift({id: 'none', text: 'Select One', disabled: true, selected: true})
this.$el.append('<h2 class="pageHeader">Inquiry Content</h2>')
this.$el.append('<select id="styles"></select>')
this.$stylesDropdown = $('#styles')
this.$stylesDropdown.select2(
{
data: data,
dropdownAutoWidth: true,
width: 'element',
minimumResultsForSearch: 10
}
)
this.$el.append('<div id="navWrapper"></div>')
this.$el.append('<div id="tNavigation"></div>')
this.$navWrapper = $('#navWrapper')
this.$tNavigation = $('#tNavigation')
this.$navWrapper.append(this.$tNavigation)
this.$el.append('<div id="editorDescription"></div>')
},
renderTabs: function (id) {
const style = this.inquiryContent.findWhere({id: id.currentTarget.value})
if (this.clearTabPanel()) {
this.clearTabs()
this.tabsView = new TabsView({style: style})
this.$tNavigation.append(this.tabsView.el)
}
},
renderTabPanel (e) {
const tabModel = this.tabsView.tabClicked(e.currentTarget.id)
if (tabModel && this.clearTabPanel()) {
this.tabPanel = new TabPanelView({model: tabModel})
this.$tNavigation.append(this.tabPanel.render().el)
}
},
clearTabs: function () {
if (this.tabsView !== undefined && this.tabsView !== null) {
this.tabsView.remove()
}
},
clearTabPanel: function () {
if (this.tabPanel !== undefined && this.tabPanel !== null) {
if (this.tabPanel.dataEditor !== undefined && this.tabPanel.dataEditor.unsavedChanges) {
if (!confirm('You have unsaved changes that will be lost if you leave the page. '
+ 'Are you sure you want to leave the page without saving your changes?')) {
return false
}
this.tabPanel.dataEditor.unsavedChanges = false
}
this.tabPanel.remove()
}
return true
}
}
)
I am trying to render the subview adding this method:
renderDescription () {
this.$editorDescription = $('#editorDescription')
this.descView = new DescView({model: this.model})
this.$editorDescription.append(this.descView)
this.$editorDescription.html(DescView.render().el)
}
It has to be rendered in a div element with id='editorDescription'
but I receive Uncaught ReferenceError: DescView is not defined
Here is how DescView is implemented:
window.DescView = Backbone.View.extend(
{
el: $('#editorDescription'),
initialize: function () {
_.bindAll(this, 'render')
this.render()
},
render: function () {
$('#editorDescriptionTemplate').tmpl(
{
description: this.model.get('description')})
.appendTo(this.el)
}
);
What am I doing wrong?
Your implementation of the DescView is incomplete. You are missing a bunch of closing braces and brackets. That's why it's undefined.

Calling toastr makes the webpage jump to top of page

I'm seeking a solution for the toastr.js "error" that causes the webpage, if scrolled down, to jump up again when a new toastr is displayed
GitHub page containing the script
I've tried to change the top to auto, but that wasn't an accepted parameter, because nothing showed up then.
Isn't there any way to make it appear where the mouse is at the moment?
.toast-top-center {
top: 12px;
margin: 0 auto;
left: 43%;
}
this has the calling code:
<p><span style="font-family:'Roboto','One Open Sans', 'Helvetica Neue', Helvetica, sans-serif;color:rgb(253,253,255); font-size:16px ">
xxxxxxxxxxxxx
</span></p>
This is the function code:
<script type='text/javascript'> function playclip() {
toastr.options = {
"debug": false,
"positionClass": "toast-top-center",
"onclick": null,
"fadeIn": 800,
"fadeOut": 1000,
"timeOut": 5000,
"extendedTimeOut": 1000
}
toastr["error"]("This link is pointing to a page that hasn't been written yet,</ br> sorry for the inconvenience?"); } </script>
And this is the script itself:
/*
* Toastr
* Copyright 2012-2015
* Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
* All Rights Reserved.
* Use, reproduction, distribution, and modification of this code is subject to the terms and
* conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
*
* ARIA Support: Greta Krafsig
*
* Project: https://github.com/CodeSeven/toastr
*/
/* global define */
(function (define) {
define(['jquery'], function ($) {
return (function () {
var $container;
var listener;
var toastId = 0;
var toastType = {
error: 'error',
info: 'info',
success: 'success',
warning: 'warning'
};
var toastr = {
clear: clear,
remove: remove,
error: error,
getContainer: getContainer,
info: info,
options: {},
subscribe: subscribe,
success: success,
version: '2.1.3',
warning: warning
};
var previousToast;
return toastr;
////////////////
function error(message, title, optionsOverride) {
return notify({
type: toastType.error,
iconClass: getOptions().iconClasses.error,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function getContainer(options, create) {
if (!options) { options = getOptions(); }
$container = $('#' + options.containerId);
if ($container.length) {
return $container;
}
if (create) {
$container = createContainer(options);
}
return $container;
}
function info(message, title, optionsOverride) {
return notify({
type: toastType.info,
iconClass: getOptions().iconClasses.info,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function subscribe(callback) {
listener = callback;
}
function success(message, title, optionsOverride) {
return notify({
type: toastType.success,
iconClass: getOptions().iconClasses.success,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function warning(message, title, optionsOverride) {
return notify({
type: toastType.warning,
iconClass: getOptions().iconClasses.warning,
message: message,
optionsOverride: optionsOverride,
title: title
});
}
function clear($toastElement, clearOptions) {
var options = getOptions();
if (!$container) { getContainer(options); }
if (!clearToast($toastElement, options, clearOptions)) {
clearContainer(options);
}
}
function remove($toastElement) {
var options = getOptions();
if (!$container) { getContainer(options); }
if ($toastElement && $(':focus', $toastElement).length === 0) {
removeToast($toastElement);
return;
}
if ($container.children().length) {
$container.remove();
}
}
// internal functions
function clearContainer (options) {
var toastsToClear = $container.children();
for (var i = toastsToClear.length - 1; i >= 0; i--) {
clearToast($(toastsToClear[i]), options);
}
}
function clearToast ($toastElement, options, clearOptions) {
var force = clearOptions && clearOptions.force ? clearOptions.force : false;
if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
$toastElement[options.hideMethod]({
duration: options.hideDuration,
easing: options.hideEasing,
complete: function () { removeToast($toastElement); }
});
return true;
}
return false;
}
function createContainer(options) {
$container = $('<div/>')
.attr('id', options.containerId)
.addClass(options.positionClass);
$container.appendTo($(options.target));
return $container;
}
function getDefaults() {
return {
tapToDismiss: true,
toastClass: 'toast',
containerId: 'toast-container',
debug: false,
showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
showDuration: 300,
showEasing: 'swing', //swing and linear are built into jQuery
onShown: undefined,
hideMethod: 'fadeOut',
hideDuration: 1000,
hideEasing: 'swing',
onHidden: undefined,
closeMethod: false,
closeDuration: false,
closeEasing: false,
closeOnHover: true,
extendedTimeOut: 1000,
iconClasses: {
error: 'toast-error',
info: 'toast-info',
success: 'toast-success',
warning: 'toast-warning'
},
iconClass: 'toast-info',
positionClass: 'toast-top-right',
timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
titleClass: 'toast-title',
messageClass: 'toast-message',
escapeHtml: false,
target: 'body',
closeHtml: '<button type="button">×</button>',
closeClass: 'toast-close-button',
newestOnTop: true,
preventDuplicates: false,
progressBar: false,
progressClass: 'toast-progress',
rtl: false
};
}
function publish(args) {
if (!listener) { return; }
listener(args);
}
function notify(map) {
var options = getOptions();
var iconClass = map.iconClass || options.iconClass;
if (typeof (map.optionsOverride) !== 'undefined') {
options = $.extend(options, map.optionsOverride);
iconClass = map.optionsOverride.iconClass || iconClass;
}
if (shouldExit(options, map)) { return; }
toastId++;
$container = getContainer(options, true);
var intervalId = null;
var $toastElement = $('<div/>');
var $titleElement = $('<div/>');
var $messageElement = $('<div/>');
var $progressElement = $('<div/>');
var $closeElement = $(options.closeHtml);
var progressBar = {
intervalId: null,
hideEta: null,
maxHideTime: null
};
var response = {
toastId: toastId,
state: 'visible',
startTime: new Date(),
options: options,
map: map
};
personalizeToast();
displayToast();
handleEvents();
publish(response);
if (options.debug && console) {
console.log(response);
}
return $toastElement;
function escapeHtml(source) {
if (source == null) {
source = '';
}
return source
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
function personalizeToast() {
setIcon();
setTitle();
setMessage();
setCloseButton();
setProgressBar();
setRTL();
setSequence();
setAria();
}
function setAria() {
var ariaValue = '';
switch (map.iconClass) {
case 'toast-success':
case 'toast-info':
ariaValue = 'polite';
break;
default:
ariaValue = 'assertive';
}
$toastElement.attr('aria-live', ariaValue);
}
function handleEvents() {
if (options.closeOnHover) {
$toastElement.hover(stickAround, delayedHideToast);
}
if (!options.onclick && options.tapToDismiss) {
$toastElement.click(hideToast);
}
if (options.closeButton && $closeElement) {
$closeElement.click(function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
event.cancelBubble = true;
}
if (options.onCloseClick) {
options.onCloseClick(event);
}
hideToast(true);
});
}
if (options.onclick) {
$toastElement.click(function (event) {
options.onclick(event);
hideToast();
});
}
}
function displayToast() {
$toastElement.hide();
$toastElement[options.showMethod](
{duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
);
if (options.timeOut > 0) {
intervalId = setTimeout(hideToast, options.timeOut);
progressBar.maxHideTime = parseFloat(options.timeOut);
progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
if (options.progressBar) {
progressBar.intervalId = setInterval(updateProgress, 10);
}
}
}
function setIcon() {
if (map.iconClass) {
$toastElement.addClass(options.toastClass).addClass(iconClass);
}
}
function setSequence() {
if (options.newestOnTop) {
$container.prepend($toastElement);
} else {
$container.append($toastElement);
}
}
function setTitle() {
if (map.title) {
var suffix = map.title;
if (options.escapeHtml) {
suffix = escapeHtml(map.title);
}
$titleElement.append(suffix).addClass(options.titleClass);
$toastElement.append($titleElement);
}
}
function setMessage() {
if (map.message) {
var suffix = map.message;
if (options.escapeHtml) {
suffix = escapeHtml(map.message);
}
$messageElement.append(suffix).addClass(options.messageClass);
$toastElement.append($messageElement);
}
}
function setCloseButton() {
if (options.closeButton) {
$closeElement.addClass(options.closeClass).attr('role', 'button');
$toastElement.prepend($closeElement);
}
}
function setProgressBar() {
if (options.progressBar) {
$progressElement.addClass(options.progressClass);
$toastElement.prepend($progressElement);
}
}
function setRTL() {
if (options.rtl) {
$toastElement.addClass('rtl');
}
}
function shouldExit(options, map) {
if (options.preventDuplicates) {
if (map.message === previousToast) {
return true;
} else {
previousToast = map.message;
}
}
return false;
}
function hideToast(override) {
var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
var duration = override && options.closeDuration !== false ?
options.closeDuration : options.hideDuration;
var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
if ($(':focus', $toastElement).length && !override) {
return;
}
clearTimeout(progressBar.intervalId);
return $toastElement[method]({
duration: duration,
easing: easing,
complete: function () {
removeToast($toastElement);
clearTimeout(intervalId);
if (options.onHidden && response.state !== 'hidden') {
options.onHidden();
}
response.state = 'hidden';
response.endTime = new Date();
publish(response);
}
});
}
function delayedHideToast() {
if (options.timeOut > 0 || options.extendedTimeOut > 0) {
intervalId = setTimeout(hideToast, options.extendedTimeOut);
progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
}
}
function stickAround() {
clearTimeout(intervalId);
progressBar.hideEta = 0;
$toastElement.stop(true, true)[options.showMethod](
{duration: options.showDuration, easing: options.showEasing}
);
}
function updateProgress() {
var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
$progressElement.width(percentage + '%');
}
}
function getOptions() {
return $.extend({}, getDefaults(), toastr.options);
}
function removeToast($toastElement) {
if (!$container) { $container = getContainer(); }
if ($toastElement.is(':visible')) {
return;
}
$toastElement.remove();
$toastElement = null;
if ($container.children().length === 0) {
$container.remove();
previousToast = undefined;
}
}
})();
});
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
if (typeof module !== 'undefined' && module.exports) { //Node
module.exports = factory(require('jquery'));
} else {
window.toastr = factory(window.jQuery);
}
}));
Change your code to be like this:
<a href="#" style="color: rgb(255,0,0,0)" onclick="playclip(); return false;" >xxxxxxxxxxxxx </a>
However, I would reconsider using this type of javascript invokation. Take a look at this "javascript:void(0);" vs "return false" vs "preventDefault()"

Didn't Get the updated value in data source.read function

My problem is that I'm setting the value in the filterA function on change event but when I call this.datasource.read() in the filterB function i don't get the updated value. My code so far:
function FilterA(element) {
element.kendoDropDownList({
dataSource: {
transport: {
read: '#Url.Action("Filter_A")'
}
},
change: function (e) {
var index = 1;
var temp = "";
$(".k-input").each(function () {
if (index === 3) {
temp = $(this).text();
}
index++;
});
index = 1;
$('#hdntemp').val(temp);
},
optionLabel: "--Select Value--"
});
}
function FilterB(element) {
element.kendoDropDownList({
dataSource: {
transport: {
read: '#Url.Action("Filter_B")' + "?temp=" + $('#hdntemp').val()
}
},
open: function (e) {
this.dataSource.read();
},
optionLabel: "--Select Value--"
});
}
i found the solution
save the datasource element somewhere globally in oncreate function and call the function in onchange funciton to get cascading effect.

"TypeError: document is undefined" with jquery-1.10.2.js

I am creating a BackboneJS project. It works fine in Chrome and Safari, but in Firefox I get errors that stop my app from loading and I cannot work out why.
The error is in my jQuery file but it is obviously something in my app that is triggering it because the jQuery library is fine on its own.
It is throwing an error on the second line of the jQuery "createSafeFragment" method:
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment();
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
My main.js that runs the app:
Backbone.View.prototype.close = function () {
if (this.beforeClose) {
this.beforeClose();
}
this.remove();
this.unbind();
};
var AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'login' : 'login',
'register' : 'register',
'rosters' : 'rosters',
'workplaces' : 'workplaces',
'groups' : 'groups',
'shifts' : 'shifts',
'logout' : 'logout'
},
content : '#content',
initialize: function () {
window.headerView = new HeaderView();
$('.header').html(window.headerView.render().el);
},
home: function () {
window.homePage = window.homePage ? window.homePage : new HomePageView();
app.showView( content, window.homePage);
window.headerView.select('home');
},
register: function () {
window.registerPage = window.registerPage ? window.registerPage : new RegisterPageView();
app.showView( content, window.registerPage);
window.headerView.select('register');
},
login: function() {
app.showView( content, new LoginPageView());
window.headerView.select('login');
},
rosters: function () {
if(Utils.checkLoggedIn()){
app.showView( content, new RosterPageView());
window.headerView.select('rosters');
}
},
groups: function () {
if(Utils.checkLoggedIn()){
app.showView( content, new GroupsPageView());
window.headerView.select('groups');
}
},
shifts: function () {
if(Utils.checkLoggedIn()){
app.showView( content, new ShiftsPageView());
window.headerView.select('shifts');
}
},
workplaces: function () {
if(Utils.checkLoggedIn()){
app.showView( content, new WorkplacesPageView());
window.headerView.select('workplaces');
}
},
logout: function () {
window.headerView.toggleLogin(false);
this.login();
},
showView: function(selector, view) {
if (this.currentView)
this.currentView.close();
$(selector).html(view.render().el);
this.currentView = view;
return view;
}
});
Utils.loadTemplates(['HomePageView', 'HeaderView', 'LoginPageView', 'RegisterPageView',
'RostersPageView', 'GroupsPageView', 'ShiftsPageView', 'UserListView',
'GroupListView', 'ShiftListView', 'SearchedUserListView', 'SearchedGroupListView',
'GroupRosterView', 'RosterListView', 'WorkplacesPageView', 'WorkplaceListView',
'SearchedWorkplaceListView', 'RosterJoinListView', 'GroupUserListView',
'WorkplaceRosterView', 'WorkplaceUserListView', 'RosterShiftView'], function(){
app = new AppRouter();
Backbone.history.start();
});
And my Util.js:
Utils = {
//template stuff
templates: {},
loadTemplates: function(names, callback) {
var that = this;
var loadTemplate = function(index) {
var name = names[index];
$.get('tpl/' + name + '.html', function(data) {
that.templates[name] = data;
index++;
if (index < names.length) {
loadTemplate(index);
} else {
callback();
}
});
};
loadTemplate(0);
},
get: function(name) {
return this.templates[name];
},
//error stuff
showAlertMessage: function(message, type){
$('#error').html(message);
$('.alert').addClass(type);
$('.alert').show();
},
showErrors: function(errors) {
_.each(errors, function (error) {
var controlGroup = $('.' + error.name);
controlGroup.addClass('error');
controlGroup.find('.help-inline').text(error.message);
}, this);
},
hideErrors: function () {
$('.control-group').removeClass('error');
$('.help-inline').text('');
},
//validator stuff
validateModel: function(model, attrs){
Utils.hideErrors();
var valError = model.validate(attrs);
if(valError){
Utils.showErrors(valError);
return false;
}
return true;
},
//loading stuff
toggleLoading: function(toggle){
$('#loading').css('visibility', toggle ? 'visible' : 'hidden');
},
//login stuff
login: function(auth){
window.headerView.toggleLogin(true);
Backbone.history.navigate("", true);
},
checkLoggedIn: function(){
if(!window.userId){
window.headerView.toggleLogin(false);
Backbone.history.navigate("login", true);
return false;
}
return true;
},
//util methods
formatDate: function(date){
var formattedDate = '';
formattedDate += date.getFullYear() + '-';
formattedDate += date.getMonth()+1 + '-';
formattedDate += date.getDate();
return formattedDate;
},
formatDateForDisplay: function(date){
var formattedDate = '';
formattedDate += date.getDate() + '/';
formattedDate += date.getMonth()+1 + '/';
formattedDate += date.getFullYear() + ' - ';
formattedDate += ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'][date.getDay()];
return formattedDate;
},
formatDateForGroup: function(date){
var formattedDate = '';
formattedDate += date.getDate() + '/';
formattedDate += date.getMonth()+1;
return formattedDate;
},
showPopup: function(id, buttons, title, content){
var popup = $(id);
popup.dialog({
modal: true,
title: title,
buttons: buttons
});
popup.find('#popupContent').html(content);
}
};
Someone please help me as this is driving me crazy! Firefox only...
I was also experiencing this problem. You can reproduce this error by doing:
$(window).append('bla');
Mine was cause by a combination of this:
click
and
function doIt(){
var newElm = $('<span>hi</span>');
$(this).append(newElm);
//now this === window, and not what I was expecting the a-element
}
This all happened because I expected the click would have been binded in a proper more-jquery-ish way to the a element. But someone decided to use 1999 code ;p. I expected for the method to be bound like this:
$("a").click(doIt);
In which case this would have been bound to the a-element and not to the window.
benhowdle89 figured out that I was appending to content when I should have been appending to this.content.
It is also a good idea to always use JSFiddle I have realised, so other people can see your problem on their own.
Thanks to benhowdle89!

module pattern and document.ready

I have started learning the javascript module pattern and I have the following code:
// PersonalInformation.js
var PersonallInformation = (function () {
$.validator.addMethod("checkPhoneNumber", function (value, element) {
if (!value) return true;
return /^((\+7)|8)(700|701|702|705|707|712|713|717|718,721|725|726|727|777)[0-9]{7}$/.test(value);
}, "Wrong phone format");
function updateQTip() {
$('div.invalid_form').qtip({
content: function (api) {
var text = $(this).prev();
return "<div class='tip_cont'><span class='simple cost'><span class='corner'></span>" + $(text).attr('data-description') + "</span></div>";
},
position: {
target: 'mouse',
adjust: { x: 5, y: 17 }
},
style: {
tip: { corner: false }
}
});
}
function updateError() {
$('.invalid_form').closest('.wrap_input').addClass('error');
$('#reg_form_pay input').each(function(element) {
if ($(this).hasClass('invalid_form')) {
$(this).closest('.wrap_input').addClass('error');
} else {
$(this).closest('.wrap_input').removeClass('error');
}
});
updateQTip();
}
function validateForm() {
$("#reg_form_pay").validate({
rules: {
Email: { required: true, email: true },
PhoneNumber: { required: true, checkPhoneNumber: true },
FirstName: { required: true },
Surname: { required: true }
},
messages: {
Email: '',
PhoneNumber: '',
FirstName: '',
Surname: ''
},
errorClass: "invalid_form",
errorElement: "div",
errorPlacement: function (error, element) {
error.insertAfter(element);
},
onkeyup: false,
showErrors: function (errorMap, errorList) {
this.defaultShowErrors();
updateError();
}
});
}
function privateInit() {
validateForm();
console.log('init ok');
}
return {
init: privateInit,
};
}());
To make this code work I have to call the init method in the view as follows:
<script>
$(document).ready(function() {
PersonallInformation.init();
})
</script>
Is it possible to avoid having to call init in the view?
UPDATE:
I have rewritten it in the following way:
function library(module) {
$(function() {
if (module.init) {
module.init();
}
});
return module;
}
var PersonallInformation = library(function () {
...
The short answer is no
your validateForm method uses the DOM to do it's work. If you call the init method prior to document.ready the behavior is unspecified.
You will have to call some method in document.ready.
You are not really using the module partern since you are in effect just encapsulating function in another function so you would have the same kind of encapsulation if you moved the entire code between (function (){...}()) to document.ready in which case you could change the last part of the function to
validateForm();
console.log('init ok');
Ie inline the init function.
EDIT
A rewrite could be something like:
var setupValidate = (function () {
return function(options) {
var defaultOptions = {
qtipOptions : {
content: function (api) {
var text = $(this).prev();
return "<div class='tip_cont'><span class='simple cost'><span class='corner'></span>" + $(text).attr('data-description') + "</span></div>";
},
position: {
target: 'mouse',
adjust: { x: 5, y: 17 }
},
style: {
tip: { corner: false }
}
},
formSelector : "#reg_form_pay",
invalidFormSelector : 'div.invalid_form',
};
options = $.extend(defaultOptions,options);
$.validator.addMethod("checkPhoneNumber", function (value, element) {
if (!value) return true;
return /^((\+7)|8)(700|701|702|705|707|712|713|717|718,721|725|726|727|777)[0-9]{7}$/.test(value);
}, "Wrong phone format");
function updateQTip() {
$(options.invalidFormSelector).qtip();
}
function updateError() {
$(options.invalidFormSelector).closest('.wrap_input').addClass('error');
$(options.formSelector).find("input").each(function(element) {
if ($(this).hasClass('invalid_form')) {
$(this).closest('.wrap_input').addClass('error');
} else {
$(this).closest('.wrap_input').removeClass('error');
}
});
updateQTip();
}
function validateForm() {
$(formSelector).validate({...});
}
validateForm();
console.log('init ok');
}
}());
and you'd then call it like:
$(function(){
setupValidate (/*with options if you'd like to change the default*/);
});

Categories

Resources