In a Jquery code I've the following situation:
$("#input_field").on('input', function () {
setTimeout(function (e) {
$.post("endpoint.php", $('#main').serialize(), function (response) {
parseRes(response);
});
}, 1);
});
$("#input_field").on("paste", function () {
setTimeout(function (e) {
$.post("endpoint.php", $('#main').serialize(), function (response) {
parseRes(response);
});
}, 1);
});
The only different thing is the event ("input" or "paste").
Is there any way to avoid this kind of repetitions (eg. adding more events to ONE code block)?
Try,
$("#input_field").on('input paste',function() {
setTimeout(function(e) {
$.post("endpoint.php", $('#main').serialize(), function (response) {
parseRes(response);
});
}, 1);
});
Please read here to know more about .on()
From the documentation:
.on( events [, selector ] [, data ], handler(eventObject) )
events: One or more space-separated event types and
optional namespaces, such as "click" or "keydown.myPlugin".
This means your code simply boils down to:
$("#input_field").on('input paste',function() {
// ...
});
Related
When user clicks on .step, the jquery will execute the hello function which works fine. The hello function will call hi function => I got error here: Hi is not a function
jQuery(document).ready(function( $ ) {
const form = {
init: function() {
$('.step').on('click', this.hello)
},
hello: function() {
console.log('Index: ', $(this).index()); // I can get the right index
this.hi(); // ERROR: Hi is not a function!
},
hi: function() {
console.log('HI')
},
}
form.init()
})
When I put the code like this, it works fine
jQuery(document).ready(function( $ ) {
const form = {
init: function() {
$('.step').on('click', this.hi) // Look here
},
hi: function() {
console.log('HI')
},
}
form.init()
})
Can you guys explain why?
Hi is not a function
Can any one explain why?
In this code
init: function() {
$('.step').on('click', this.hello)
},
hello: function() {
console.log('Index: ', $(this).index()); // I can get the right index
this.hi(); // ERROR: Hi is not a function!
},
you setup form.hello as an event handler for the click event. Within event handlers, this is the element that was clicked, as in:
$("button").click(function() { console.log(this.id); }
the button will (given this code) not have a .hi method.
How can we avoid the binding using Es6 or arrow function?
If you don't need to know which button was clicked, you can use an arrow function when defining the event handler:
init: function() {
$('.step').on('click', () => this.hello())
},
Example: https://jsfiddle.net/mcuh5awt/2/
Ideally, you'll want to access both the button and the form class, this is possible in two ways, the first is to change how you define your class, but keeping with how you've done it, we can add a new property self to store a reference to its ...well... self...
jQuery(document).ready(function( $ ) {
const form = {
self : {},
init: function() {
self = this;
$('.step').on('click', self.hello)
},
hello: function() {
console.log('Index: ', $(this).index());
self.hi();
},
hi: function() {
console.log('HI')
},
}
form.init()
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<button class='step' type='button'>
Step 1
</button>
<button class='step' type='button'>
Step 2
</button>
</div>
As this becomes a public property of your class, you may prefer a different name in this case eg form to match the class name.
I am using reveal module pattern but can't call the method.
$(function () {
$(document).on("click", '.EditBill', function () {
editModule.EditBill(this);
});
});
var editModule = (function () {
function EditBill(object) {
var itemId = $(object).data('itemid');
loader.show();
$.ajax({
url: 'Bill/Edit',
data: { id: ItemId },
success: function (data) {
loader.hide();
$('#ModelPopup').empty();
$('#ModelPopup').html(data);
$(function () {
$('#editModal').modal();
});
}
});
}
return
{
EditBill: EditBill
}
}());
When I debug in Edge, I click the button ('.EditBill'), the message is
> SCRIPT5007: Unable to get property 'EditBill' of undefined or null
Thanks for Shyju, the answer is return and the first curly brace '{', should be on the same line! It works now. I don't understand why I have to follow this syntas, but it works.
I have been trying to fire a custom event when a file has been successfully uploaded using a modal window. A grid on the main page listens for the event and should reload its store when a file is successfully uploaded. Problem is, the grid never catches this event.
I think I have a fundamental misunderstanding of how custom events work. What steps should I take to get back on track?
SomeCommonUtilityClass.js
upload: function(args) {
Ext.create('Ext.window.Window', {
/* form with some controls */
buttons: [{
text:'Upload',
handler: function() {
var win = this.up('window');
var form = this.up('form').getForm();
form.submit ({
url: myAjaxCall,
success: function() {
/* fire event here */
win.fireEvent('uploadSuccess');
},
failure: function() {
/*...*/
}
});
}
},
/* etc. */
});
}
SomeOtherFileView.js
{
xtype:'grid',
itemId:'uploadedGrid',
listeners: {
uploadSuccess: 'reloadUploadStore'
},
bind: {
store:'{form}'
},
columns:[/*...*/]
}
SomeOtherFileViewController.js
reloadUploadStore: function() {
console.log("My event fired!") // Never gets here.
/* .... */
store.load({
params: ({
a: "a",
b: "b"
});
callback: function() {
/* do more stuff */
}
});
}
SomeCommonUtilityClass
win.fireEvent('uploadSuccess');
Example of custom event and Controller that listen on it:
SomeOtherFileViewController
init: function() {
this.listen({
// We are using Controller event domain here
controller: {
// This selector matches any originating Controller
'*': {
uploadSuccess: 'reloadUploadStore'
}
}
});
},
reloadUploadStore: function() {
//your code
}
or if you want pass a argument:
win.fireEvent('uploadSuccess',extraArgument);
Controller code is the same. Only your function definition changes:
reloadUploadStore: function(yourArgument) {
//Do your stuff with extraArgument
}
I've just developed this JavaScript/Backbone module as a part of a web page I am developing. I would like to create a Jasmine test for it, but I am brand new to Jasmine, therefore I am not sure what should I be testing in this class. What should be the "skeleton" of the test? In order to avoid redundancy in tests, what parts will you test?
editdestinationview.js:
define([
'common/jqueryex',
'backbone',
'marionette',
'handlebars',
'text!education/eet/templates/editdestination.hb',
'text!common/templates/validationerror.hb',
'lang/languageinclude',
'common/i18nhelper'
], function ($, Backbone, Marionette, Handlebars, templateSource, errorTemplateSource, i18n) {
'use strict';
var errorTemplate = Handlebars.compile(errorTemplateSource),
EditDestinationView = Marionette.ItemView.extend({
initialize: function (options) {
this._destinationTypes = options.destinationTypes;
},
onRender: function () {
this.stickit();
this._bindValidation();
},
_bindValidation: function () {
Backbone.Validation.bind(this, {
valid: this._validAttributeCallback,
invalid: this._invalidAttributeCallback,
forceUpdate: true
});
},
_validAttributeCallback: function (view, attr) {
view.$('#error-message-' + attr).remove();
},
_invalidAttributeCallback: function (view, attr, error) {
view.$('#error-message-' + attr).remove();
view.$('#destinationTypes').parent('div').append(errorTemplate({
attr: attr,
error: error
}));
},
template: Handlebars.compile(templateSource),
ui: {
saveAnchor: '#ed_eetSaveDestinationAnchor',
deleteAnchor: '#ed_eetDeleteDestinationIcon'
},
triggers: {
'click #ui.saveAnchor': 'click:saveDestination',
'click #ui.deleteAnchor': 'click:deleteDestination'
},
bindings: {
'select#destinationTypes': {
observe: 'destinationTypeId',
selectOptions: {
collection: function () {
return this._destinationTypes;
},
labelPath: 'description',
valuePath: 'destinationTypeId',
defaultOption: {label: i18n.EDUCATION_EET_SELECT_INTENDED_DESTINATION, value: null}
}
}
}
});
return EditDestinationView;
});
Thanks everyone!
UPDATE:
After thinking a lot about it, I think that I should try these aspects:
-Triggers: Check if they can be clicked.
-"_validAttributeCallback" and "_invalidAttributeCallback": Check if they behave accordingly to the code.
-Template: Spy on it to check if it is performing it's mission. (Optional test)
So, the test skeleton will be:
define([
'education/eet/views/editdestinationview'
], function (EditDestinationView) {
describe('description...', function () {
beforeEach(function () {
//EditDestinationView.triggers
});
describe('blablabla', function () {
beforeEach(function () {
// ...
});
it('blablabla', function () {
// blablabla
});
});
});
});
Any help on how to test this please?
One common pattern is to use two describe statements, one for the class and one for the method being tested, and then an it statement for each thing you want to test about that method. The rspec people have a convention (which I use in my JS tests) of using a '#' on the method describe for an instance method, and a "." for a describe of a static method.
Now, if you adopt all of the above, and you want to test (for instance) that your View's click-handling method triggers a certain event on the View's Model, it would look something like this:
define([
'education/eet/views/editdestinationview'
], function (EditDestinationView) {
describe('EditDestinationView', function () {
var view;
beforeEach(function () {
// do setup work that applies to all EditDestinationView tests
view = new EditDestinationView({model: new Backbone.Model()});
});
describe('#handleClick', function () {
beforeEach(function () {
// do setup work that applies only to handleClick tests
});
it('triggers a foo event', function () {
var wasTriggered;
view.model.on('foo', function() {
wasTriggered = true;
});
view.handleClick();
expect(wasTriggered).toBe(true);
});
});
});
});
P.S. Instead of creating a fake "foo" handler like I did, most people use a mocking library like Sinon. Using that library our "it" statement could instead be:
it('triggers a foo event', function () {
var triggerStub = sinon.stub(view.model, 'trigger');
view.handleClick();
expect(triggerStub.calledOnce).toBe(true);
expect(triggerStub.args[0][0]).toBe('foo');
//NOTE: args[0][0] == first arg of first call
});
I just would like to put color on div by addClass event and then it should fade in.
$("#box1").hover(
function () {
$("#box2").addClass("blue");
$("#box3").addClass("yellow");
},
function () {
$("#box2").removeClass("blue");
$("#box3").removeClass("yellow");
}
);
$("#box2").hover(
function () {
$("#box1").addClass("blue");
$("#box4").addClass("yellow");
},
function () {
$("#box1").removeClass("blue");
$("#box4").removeClass("yellow");
}
);
I know it's pretty ugly but it's worked :
$('#box1').hover(function () {
$("#box2").fadeOut(0).addClass('blue').fadeIn(300);
},
function () {
$("#box2").fadeOut(300).queue(function(){ $(this).removeClass('blue').fadeIn(0).dequeue()});
});
Demo here : JSFIDDLE