smart way to rewrite this function - jquery-selectors

I have this, and I am showing a div if user clicked one button and not showing it if the user clicked other. Its working but its dumb to do this way with repeatition
$j(document).ready(function() {
$j('#Button1').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
$j("#Response").show();
});
});
$j('#Button21').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
//do something else
});
});
});

I'd do it by adding a class to the selected buttons and then pull the event.target id from the click function:
$j('.buttons').click(function(e) {
var buttonId = e.target.id,
data = $j("form").serialize();
$j.post('file.php', data, function(response) {
switch (buttonId) {
case "Button1":
$j("#Response").show();
break;
case "Button21":
//do something else
break;
}
});
});

You need to abstract the data from the functionality.
sendClick('#Button1', function() {
$j('#Response').show();
});
sendClick('#Button21', function() {
// do something
});
sendClick function
function sendClick(selector, callback)
{
$j(selector).click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, callback);
});
}
This way you can repeat the same functionality over and over by changing the selector and the callback. You could customise this even further by:
function sendClick(selector, options, callback)
{
// handle arguments
if(typeof options == 'function') {
callback = options;
options = {};
} else {
options = options || {};
}
$j.extend({
form: 'form',
file: 'file.php'
}, options);
// abstracted logic
$j(selector).click(function() {
var data = $j(options.form).serialize();
$j.post(options.file, data, callback);
});
}
then use like
sendClick('#select', {form: '#anotherForm'}, function() {
// do something
});
or
sendClick('#another', function(response) {
// something else
});

You can attach the event to both, and then, when you need to check which element triggered the event, use event.target.
$j(function() {
$j('#Button1, #Button2').click( function (event) {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
if ($(event.target).is('#Button1')) {
$j("#Response").show();
} else {
// Do something else
}
});
});
});

Here are two different ways:
You can combine the two handlers into one handler:
$j(document).ready(function () {
$j('#Button1, #Button21').click(function() {
var id = this.id;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
if (id == 'Button1') {
// Show
} else {
// Do something else
}
});
});
});
Or write a special kind of handler:
$j.fn.clickAndPost = function (handler) {
this.click(function () {
var me = this;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
handler.call(me);
});
});
});
...and attach two of them:
$j(document).ready(function () {
$j('#Button1').clickAndPost(function () {
// Show
});
$j('#Button21').clickAndPost(function () {
// Do something else
});
});

$j(function($) {
$('#Button1', '#Button21').click(function() {
var that = this,
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that.id === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});

$(document).ready(function() {
$('#Button1 #Button21').click(function() {
var that = this.attr("id");
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});
Let me know if it's not working.

Related

Calling mongodb insert,find functions from another class in react native , returns undefined

This is my first class where I defined all db functions.
import React,{Component} from 'react';
var Datastore = require('react-native-local-mongodb')
, db = new Datastore({ filename: 'asyncStorageKey', autoload: true });
export default class RDDBManager {
static dbmanager = null;
static getInstance() {
if (RDDBManager.dbmanager == null) {
RDDBManager.dbmanager = new RDDBManager();
}
return this.dbmanager;
}
constructor () {
}
//insert items
insertItem(item){
var json = item.toJsonString();
console.log("Inside insertItem ::: "+json);
db.insert(json,function(err,newDos){
return newDos;
});
}
//read single item
readItem(itemId){
db.findOne({ id: itemId }, function (err, doc) {
return doc;
});
}
//read all items
readAllItems(){
db.find({}, function (err, docs) {
return docs;
});
}
getModalData(modalName) {
this.readAllItems();
}
//update
updateItem(itemId){
db.update({ id: itemId }, { $set: { system: 'solar system' } }, { multi: true }, function (err, numReplaced) {
});
}
//delete item
deleteItem(itemId){
db.remove({ id: itemId }, {}, function (err, numRemoved) {
return numRemoved;
});
}
}
But,when I try to call these functions from another class,the data is undefined.
loadDataFromDB() {
var items = RDDBManager.getInstance().readAllItems();
console.log("Items ======>>>>>> "+items);
}
the value of items is undefined.
This is because you are not doing things right, Your readallitems is async in nature so you have to do something like this:-
//read all items
readAllItems(callback){
db.find({}, function (err, docs) {
callback(docs);
});
}
And For calling something like this:-
loadDataFromDB() {
RDDBManager.getInstance().readAllItems(function(items){
console.log("Items ======>>>>>> "+items);
});
}
Alternatively, you can use promise or Async await also.

Protractor specs leaking

I'm still quite new to promises and the like and I need some help with this problem. One of my it blocks does not end before the next one begins ending up in a StaleElementReferenceError a whole specfile later from where the code was supposed to be called.
listView.js (I know it looks weird but I set it up this way for an unrelated reason):
module.exports = function () {
var public = {};
public.checkFilters = function (filters) {
var promises = [];
for (var i = 0; i < filters.length; i++) {
promises[i] = getFilterPromise(filters[i]);
}
return protractor.promise.all(promises);
};
var getFilterPromise = function (filter) {
return public.getHeaderIndex(filter.on).then(function (headerIndex) {
return checkRows(filter.values, headerIndex);
});
};
public.getHeaderIndex = function (text) {
var headers = table.all(by.tagName('th'));
var correctHeaderIndex;
return headers.each(function (header, index) {
header.getText().then(function (actualHeaderText) {
if (actualHeaderText === text) {
correctHeaderIndex = index;
}
})
}).then(function () {
return new Promise(function (resolve, reject) {
if (correctHeaderIndex) {
resolve(correctHeaderIndex);
} else {
reject('Header not found');
}
});
});
};
public.getWorkflowCount = function () {
return workflows.count();
};
var checkRows = function (matchers, headerIndex) {
var mismatch = false;
return workflows.each(function (element, index) {
public.getTextFromCell(index, headerIndex).then(function (actual) {
if (!anyMatch(actual, matchers)) {
mismatch = true;
}
});
}).then(function () {
return new Promise(function (resolve, reject) {
if (mismatch) {
reject('Header not found');
} else {
resolve('all rows matched');
}
});
});
};
var anyMatch = function (actual, matchers) {
var match = false;
for (var j = 0; j < values.length; j++) {
if (text === values[j]) {
match = true;
}
}
return match;
};
public.getTextFromCell = function (row, column) {
return workflows.get(row).all(by.tagName('td')).get(column).getText();
};
return public;
}();
LV_00:
describe('LV_00:', function () {
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
I think you should move the test preparation code into the beforeEach():
describe('LV_00:', function () {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
You may also need to use the done callback function:
describe('LV_00:', function (done) {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress).then(function () {
done();
});
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
assuming filter() returns a promise.
Found the solution thanks to alecxe proposing to use done() I used the following after some googling around.
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
protractor.promise.controlFlow().execute(function () {
return P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
Found here: Prevent Protractor from finishing before promise has been resolved

Leaflet.js How to stop on map evnet

I am calling a function when the user has panned the map with:
$('#updateTheMap').click(function() {
if (document.getElementById('updateMap').checked) {
// stop the the dragend event...
}
else {
map.on('dragend', function() {
sortBinis(simpleFilterSql);
});
}
});
But I can not figure out how to end this event?
Use a variable:
var updateTheMap = true;
$('#updateTheMap').click(function() {
updateTheMap = document.getElementById('updateMap').checked;
});
map.on('dragend', function() {
if (updateTheMap) sortBinis(simpleFilterSql);
});
If by 'end this event' you mean 'remove the event listener' you can use map.off()
function onDragend(e) { sortBinis(simpleFilterSql); }
$('#updateTheMap').click(function() {
if (document.getElementById('updateMap').checked) {
map.off('dragend', onDragend);
}
else {
map.on('dragend', onDragend);
}
});

How to reuse jquery-ui-autocomplete cached results when appending search term?

I have the following JS method to bind the jQuery UI autocomplete widget to a search text box. Everything works fine, including caching, except that I make unnecessary server calls when appending my search term because I don't reuse the just-retrieved results.
For example, searching for "ab" fetches some results from the server. Typing "c" after "ab" in the search box fetches "abc" results from the server, instead of reusing the cached "ab" results and omitting ones that don't match "abc".
I went down the path of manually looking up the "ab" search results, filtering them using a regex to select the "abc" subset, but this totally seems like I'm reinventing the wheel. What is the proper, canonical way to tell the widget to use the "ab" results, but filter them for the "abc" term and redisplay the shortened dropdown?
function bindSearchForm() {
"use strict";
var cache = new Object();
$('#search_text_field').autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term;
if (term in cache) {
response(cache[term]);
return;
}
$.ajax({type: 'POST',
dataType: 'json',
url: '/get_search_data',
data: {q: term},
success: function (data) {
cache[term] = data;
response(data);
}
});
});
}
Here's my "brute-force, reinventing the wheel" method, which is, for now, looking like the right solution.
function bindSearchForm() {
"use strict";
var cache = new Object();
var terms = new Array();
function cacheNewTerm(newTerm, results) {
// maintain a 10-term cache
if (terms.push(newTerm) > 10) {
delete cache[terms.shift()];
}
cache[newTerm] = results;
};
$('#search_text_field').autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term.toLowerCase();
if (term in cache) {
response(cache[term]);
return;
} else if (terms.length) {
var lastTerm = terms[terms.length - 1];
if (term.substring(0, lastTerm.length) === lastTerm) {
var results = new Array();
for (var i = 0; i < cache[lastTerm].length; i++) {
if (cache[lastTerm][i].label.toLowerCase().indexOf(term) !== -1) {
results.push(cache[lastTerm][i]);
}
}
response(results);
return;
}
}
$.ajax({type: 'POST',
dataType: 'json',
url: '/get_search_data',
data: {q: term},
success: function (data) {
cacheNewTerm(term, data);
response(data);
return;
}
});
});
}
If anyone wants a version that supports multiple entries in the text box then please see below:
$(function () {
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}
var cache = new Object();
var terms = new Array();
function cacheNewTerm(newTerm, results) {
// keep cache of 10 terms
if (terms.push(newTerm) > 10) {
delete cache[terms.shift()];
}
cache[newTerm] = results;
}
$("#searchTextField")
.on("keydown",
function (event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
})
.autocomplete({
minLength: 2,
source: function (request, response) {
var term = extractLast(request.term.toLowerCase());
if (term in cache) {
response(cache[term]);
return;
} else if (terms.length) {
var lastTerm = terms[terms.length - 1];
console.log('LAst Term: ' + lastTerm);
if (term.substring(0, lastTerm.length) === lastTerm) {
var results = new Array();
for (var i = 0; i < cache[lastTerm].length; i++) {
console.log('Total cache[lastTerm[.length] = ' +
cache[lastTerm].length +
'....' +
i +
'-' +
lastTerm[i]);
console.log('Label-' + cache[lastTerm][i]);
var cachedItem = cache[lastTerm][i];
if (cachedItem != null) {
if (cachedItem.toLowerCase().indexOf(term) !== -1) {
results.push(cache[lastTerm][i]);
}
}
}
response(results);
return;
}
}
$.ajax({
url: '#Url.Action("GetSearchData", "Home")',
dataType: "json",
contentType: 'application/json, charset=utf-8',
data: {
term: extractLast(request.term)
},
success: function (data) {
cacheNewTerm(term, data);
response($.map(data,
function (item) {
return {
label: item
};
}));
},
error: function (xhr, status, error) {
alert(error);
}
});
},
search: function () {
var term = extractLast(this.value);
if (term.length < 2) {
return false;
}
},
focus: function () {
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push("");
this.value = terms.join(", ");
return false;
}
});

KnockoutJS : initial values are not posted to server when using ko.toJSON(this)?

I've this javascript viewmodel defined:
function PersonViewModel() {
// Data members
this.Name = ko.observable();
this.Function_Id = ko.observable();
this.SubFunction_Id = ko.observable();
this.Functions = ko.observableArray();
this.SubFunctions = ko.observableArray();
// Whenever the Function changes, update the SubFunctions selection
this.Function_Id.subscribe(function (id) {
this.GetSubFunctions(id);
}, this);
// Functions to get data from server
this.Init = function () {
this.GetFunctions();
this.Function_Id('#(Model.Function_Id)');
};
this.GetFunctions = function () {
var vm = this;
$.getJSON(
'#Url.Action("GetFunctions", "Function")',
function (data) {
vm.Functions(data);
}
);
};
this.GetSubFunctions = function (Function_Id) {
var vm = this;
if (Function_Id != null) {
$.getJSON(
'#Url.Action("GetSubFunctions", "Function")',
{ Function_Id: Function_Id },
function (data) {
vm.SubFunctions(data);
}
);
}
else {
vm.SubFunction_Id(0);
vm.SubFunctions([]);
}
};
this.Save = function () {
var PostData = ko.toJSON(this);
var d = $.dump(PostData);
alert(d);
$.ajax({
type: 'POST',
url: '/Person/Save',
data: PostData,
contentType: 'application/json',
success: function (data) {
alert(data);
}
});
};
}
$(document).ready(function () {
var personViewModel = new PersonViewModel();
personViewModel.Init();
ko.applyBindings(personViewModel);
});
When the Submit button is clicked, the data from the select lists is posted, but NOT the 'Function_Id'.
When I choose a different value in the Function dropdown list, and the click the Submit button, the value for 'Function_Id' is correctly posted.
How to fix this ?
It's because the scope of the this keyword in javascript
this.Init = function () {
this.GetFunctions(); // this === PersonViewModel.Init
this.Function_Id('#(Model.Function_Id)'); // calls PersonViewModel.Init.Function_Id(...)
};
You should store the refrence to the PersonViewModel instance.
var self = this;
self.Init = function () {
self.GetFunctions();
self.Function_Id('#(Model.Function_Id)'); // calls PersonViewModel.Function_Id(...)
};