I want to add AND search function to a following incremental search jQuery plugin that can search option elements from select-boxes.
JSFiddle
I'm trying to do these ideas but can't code successfully.
- first of all I want to define white space as a delimiter.
- next I want to distinguish that variable from other white spaces in option elements.
By the way, I don't want to replace a lot of DOM elements.
So, I don't want to use plugin like selectize.js, nether datalist elements anyway.
Somebody help?
(function ($, window, document, undefined) {
'use strict';
var pluginName = "selectboxsearch",
defaults = {
delay: 100,
bind: 'keyup',
};
function Plugin(element, target, options) {
this.element = element;
this.$element = $(element);
this.target = target;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.vars = {
optionRows: $(this.target).children().map(function () {
return this;
})
};
this.init();
}
Plugin.prototype = {
init: function () {
var self = this,
delay = this.options.delay;
this.$element.on(this.options.bind, function () {
var timeout = window.setTimeout(function () {
self.go();
}, delay);
});
},
go: function () {
var array = this.vars.optionRows,
val = this.$element.val();
//一周目のみ
for (var n = 0; n < 1; n++) {
// いったん削除
$(this.target).children().remove();
for (var i = 0, len = array.length; i < len; i++) {
if (array[i]) {
//option内のスペースを除去
var pos = array[i].innerHTML.toLowerCase().replace(/ /g,'').indexOf(val, 0);
// キーワードが空、もしくはヒットした場合要素追加
if ((val.replace(/ /g,'').length === 0) || pos >= 0) {
$(this.target).append(array[i]);
}
}
}
}
},
additem: function (items) {
var self = this,
array = this.vars.optionRows,
len = this.vars.optionRows.length;
$.each(items, function (index, item) {
var add = true;
for (var i = 0, len; i < len; i++) {
if (item.value == array[i].value) {
add = false;
}
}
if (add == true) {
array.push(item);
}
});
this.vars.optionRows = array;
self.go();
},
delitem: function (items) {
var self = this,
array = [];
$.each(this.vars.optionRows, function (index, item) {
var del = false;
for (var i = 0, len = items.length; i < len; i++) {
if (item.value == items[i].value) {
del = true;
}
}
if (del == false) {
array.push(item);
}
});
this.vars.optionRows = array;
self.go();
}
};
$.fn[pluginName] = function (target, options) {
return this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin($(this), target, options));
}
});
};
function _fnGetMaxLenString(settings, colIdx) {
var s, max = -1,
maxIdx = -1;
for (var i = 0, ien = settings.aoData.length; i < ien; i++) {
s = _fnGetCellData(settings, i, colIdx, 'display') + '';
s = s.replace(__re_html_remove, '');
s = s.replace(' ', ' ');
if (s.length > max) {
max = s.length;
maxIdx = i;
}
}
return maxIdx;
}
})(jQuery, window, document);
Related
Have a literal object with methods.
I want to chain the methods to each other using appendChild DOM method.
In the createStructure method if i separate the assignmentsd from each other, works.
var row = this.createRow();
row.appendChild(this.createHeadCells());
this.DBTable.appendChild(row);
If i chain the methods to each other it wont, no error message.
this.DBTable.appendChild(this.createRow().appendChild(this.createHeadCells()));
Otherwise this chaining is working:
document.body.appendChild(document.createElement('p').appendChild(document.createElement('span').appendChild(document.createTextNode('abc')));
What did i wrong?
The Code:
var readyStateCheckInterval = setInterval(function () {
if (document.readyState === "complete" || document.readyState === "loaded") {
clearInterval(readyStateCheckInterval);
init();
}
}, 10);
var DBTable =
{
DBTable : document.createDocumentFragment(),
colNum : 0,
rowNum : 0,
createTable : function(colNum, rowNum)
{
this.DBTable = document.createElement('table');
this.colNum = colNum;
this.rowNum = rowNum;
this.createTableStructure();
},
createRow : function()
{
return document.createElement('tr');
},
createHeadCells : function()
{
var df = document.createDocumentFragment();
for ( var a = 0; a < this.colNum; a++)
{
df.appendChild(document.createElement('th'));
}
return df;
},
createDataCells : function()
{
var df = document.createDocumentFragment();
for ( var a = 0; a < this.colNum; a++)
{
df.appendChild(document.createElement('td'));
}
return df;
},
createTableStructure : function()
{
var row = this.createRow();
row.appendChild(this.createHeadCells());
this.DBTable.appendChild(row);
this.DBTable.appendChild(this.createRow().appendChild(this.createHeadCells()));
/*
for ( var a = 0; a < this.rowNum; a++) {
var row = this.createRow();
row.appendChild(this.createDataCells());
this.DBTable.appendChild(row);
//this.DBTable.appendChild(this.createRow().appendChild(this.createDataCells()));
}
*/
document.body.appendChild(this.DBTable);
}
};
function init() {
DBTable.createTable(3,4);
var td = document.querySelectorAll('td');
for (var el in td) {
td[el].innerHTML = 'asdf';
}
var th = document.querySelectorAll('th');
for (var el2 in th) {
th[el2].innerHTML = 'abcd';
}
}
I'm trying to build a Javascript library like jQuery just to learn Javascript more. So far, I've developed this:
window.jsLib = function (selector) {
var about = {
Version: 0.1
};
if (selector) {
if (window === this) {
return new jsLib(selector);
}
if (typeof selector === 'string') {
var nodes = document.querySelectorAll(selector);
for (var i = 0; i < nodes.length; i++) {
this[i] = nodes[i];
}
this.length = nodes.length;
} else if (typeof selector === 'object') {
this[0] = selector;
this.length = 1;
}
return this;
} else {
return about;
}
};
And for methods, I've developed some like:
jsLib.fn = jsLib.prototype = {
css: function (key, value) {
if (value !== undefined) {
for (var i = 0; i < this.length; i++) {
this[i].style[key] = value;
}
return this;
} else {
for (var i = 0; i < this.length; i++) {
return this[i].style[key];
}
}
},
html: function (value) {
if (value !== undefined) {
for (var i = 0; i < this.length; i++) {
this[i].innerHTML = value;
}
return this;
} else {
for (var i = 0; i < this.length; i++) {
return this[i].innerHTML;
}
}
},
on: function (type, callback) {
console.log(window.event);
for (var i = 0; i < this.length; i++) {
this[i].addEventListener(type, callback, false);
}
return this;
},
trigger: function (type) {
var event = new Event(type);
for (var i = 0; i < this.length; i++) {
this[i].dispatchEvent(event);
}
return this;
},
append: function(value) {
var old = this.html();
this.html(old + '' + value);
return this;
}
};
You may have noted that I've defined a method on like jQuery.
Whenever I'm calling like jsLib('div#foo').on('click', someFunc);, it is working fine.
But, suppose I have appended some html like jsLib('body').append('<a id="#bar" href="#">Click</a>');
And then I want to provide an API to add event listener to #bar like jsLib('body').on('click', '#bar', someOtherFunc);.
But I'm not sure how to implement this listener.
Kindly help.
From your comments I suppose you request a live implementation?
If that is the case, i wold suggest you to add a data method to your object, remember all events to be registered and register them from append method, when content is appended to the current element.
I extended your library with the .data and .live methods and queued an event registration for the next span to be added in body. See the modified code snippet and check out the console to validate.
window.jsLib = function (selector) {
var about = {
Version: 0.1
};
if (selector) {
if (window === this) {
return new jsLib(selector);
}
if (typeof selector === 'string') {
var nodes = document.querySelectorAll(selector);
for (var i = 0; i < nodes.length; i++) {
this[i] = nodes[i];
}
this.length = nodes.length;
this._selector = selector;
} else if (typeof selector === 'object') {
this[0] = selector;
this.length = 1;
}
return this;
} else {
return about;
}
};
jsLib.fn = jsLib.prototype = {
css: function (key, value) {
if (value !== undefined) {
for (var i = 0; i < this.length; i++) {
this[i].style[key] = value;
}
return this;
} else {
for (var i = 0; i < this.length; i++) {
return this[i].style[key];
}
}
},
html: function (value) {
if (value !== undefined) {
for (var i = 0; i < this.length; i++) {
this[i].innerHTML = value;
}
return this;
} else {
for (var i = 0; i < this.length; i++) {
return this[i].innerHTML;
}
}
},
on: function (type, callback) {
for (var i = 0; i < this.length; i++) {
this[i].addEventListener(type, callback, false);
}
return this;
},
trigger: function (type) {
var event = new Event(type);
for (var i = 0; i < this.length; i++) {
this[i].dispatchEvent(event);
}
return this;
},
append: function(value) {
var old = this.html(),
pendingEvents = this.data('jsLib_Future_Events') || [],
registered = {};
this.html(old + '' + value);
// Attach pending events to newly added childs (if any match found)
pendingEvents.forEach(function (evConf, i) {
[].slice.call(jsLib(this._selector + ' ' + evConf.selector), 0).forEach(function (el) {
jsLib(el).on(evConf.type, evConf.callback);
registered[i] = true;
});
}.bind(this));
// Clear list of pending requests of any registered events
this.data('sLib_Future_Events', pendingEvents.filter(function (evConf, i) { return !!registered[i]; }));
return this;
},
_data: {},
data: function (key, value) {
if (arguments.length > 1) this._data[key] = arguments[1]; // Setter
return key ? this._data[key] : this._data; // Getter of key or all
},
live: function (type, selector, callback) {
this.data('jsLib_Future_Events', (this.data('jsLib_Future_Events') || []).concat({type: type, selector: selector, callback: callback}));
return this;
}
};
jsLib('body').live('click', 'span', function () { console.debug('event triggered on appendend content after live registration of event handle'); });
jsLib('body').append('<br><span>dynamic content</span>');
<div>existing content</div>
Considerations:
you will have to make a similar implementation for html method
if you want to make a real live clone you will have to keep pre-registered event definitions and register any new elements matching the selector (at this moment once an element matches the selector and the event is registered the event definition is removed in append - to make it universal you will have to mark your bound elements, use data for this)
I took js-combinatorics code and produced this:
(function(global) {
'use strict';
if (global.Combinatorics) return;
/* common methods */
var addProperties = function(dst, src) {
Object.keys(src).forEach(function(p) {
Object.defineProperty(dst, p, {
value: src[p]
});
});
};
var hideProperty = function(o, p) {
Object.defineProperty(o, p, {
writable: true
});
};
var toArray = function(f) {
var e, result = [];
this.init();
while (e = this.next()) result.push(f ? f(e) : e);
this.init();
return result;
};
var common = {
toArray: toArray,
map: toArray,
forEach: function(f) {
var e;
this.init();
while (e = this.next()) f(e);
this.init();
},
filter: function(f) {
var e, result = [];
this.init();
while (e = this.next()) if (f(e)) result.push(e);
this.init();
return result;
}
};
/* Cartesian Product */
var arraySlice = Array.prototype.slice;
var cartesianProduct = function() {
if (!arguments.length) throw new RangeError;
var args = arraySlice.call(arguments);
args = args[0];
console.log(args);
var
size = args.reduce(function(p, a) {
return p * a.length;
}, 1),
sizeOf = function() {
return size;
},
dim = args.length,
that = Object.create(args, {
length: {
get: sizeOf
}
});
if (!size) throw new RangeError;
hideProperty(that, 'index');
addProperties(that, {
valueOf: sizeOf,
dim: dim,
init: function() {
this.index = 0;
},
get: function() {
if (arguments.length !== this.length) return;
var result = [];
arguments.forEach(function(element,index,array) {
var i = arguments[index];
if(i >= this[index].length) return;
result.push(this[index][i]);
});
return result;
},
nth: function(n) {
var result = [];
arguments.forEach(function(element,index,array) {
var l = this[index].length,
i = n % l;
result.push(this[index][i]);
n -= i;
n /= l;
});
return result;
},
next: function() {
if (this.index >= size) return;
var result = this.nth(this.index);
this.index++;
return result;
}
});
addProperties(that, common);
that.init();
return that;
};
/* export */
addProperties(global.Combinatorics = Object.create(null), {
cartesianProduct: cartesianProduct
});
})(this);
var _ = [];
_[1] = [1,4];
_[7] = [2,9];
cp = Combinatorics.cartesianProduct(_);
console.log(cp.toArray());
I expect to get this result in the end:
[[1,2],[1,9],[4,2],[4,9]]
But keep getting Uncaught TypeError: undefined is not a function in Chrome and TypeError: arguments.forEach is not a function in Firefox every time I use forEach in this part of code:
nth: function(n) {
var result = [];
arguments.forEach(function(element,index,array) {
var l = this[index].length,
i = n % l;
result.push(this[index][i]);
n -= i;
n /= l;
});
return result;
}
Keeping indexes of _ array is a must.
arguments is not an Array, so it doesn't have a forEach method.
You can convert it to an array just like you did in var args = arraySlice.call(arguments);, or you use a for loop to iterate over its elements.
I needed to post the _ array with non-strict indexation:
var _ = [];
_[1] = [1,4];
_[7] = [2,9];
The default solutions are no-go, because they do not handle such arrays. So I had to tweak Bergi's idea found here:
function cartesian(arg) {
var r = [], max = arg.length-1;
function helper(arr, i) {
while(typeof arg[i] === "undefined") {
i += 1;
}
for (var j=0, l=arg[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(arg[i][j]);
if (i==max) {
r.push(a);
} else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
I have the following coded using jQuery:
$('.status-infos').click( function (e) {
var xx = $(this).attr('data-xx');
alert(xx);
return false;
});
Our site main page will no longer use jQuery and so I need to do something similar to this using only javascript.
I saw this as a way to get the click event:
document.getElementById('element').onclick = function(e){
alert('click');
}
but how can I get the xx attribute.
You can use:
document.getElementsByClassName('status-infos')
Then loop over that array and use.. onclick = function() {}
Use: element.getAttribute() to get the data attribute
Solution for modern browsers:
var els = document.querySelectorAll(".status-infos");
for (var i = 0; i < els.length; i++) {
els[i].addEventListener("click", function() {
var xx = this.getAttribute("data-xx");
alert(xx);
return false;
});
}
Here is the complete version for IE8+ as well
DEMO
function getElementsByClassName(className) {
if (document.getElementsByClassName) {
return document.getElementsByClassName(className); }
else { return document.querySelectorAll('.' + className); } }
window.onload=function() {
var statinf = getElementsByClassName("status-infos");
for (var i=0;i<statinf.length;i++) {
statinf[i].onclick=function() {
var xx = this.getAttribute('data-xx');
alert(xx);
return false;
}
}
}
jQuery has always made developers lazy.. Try this code:
/* http://dustindiaz.com/rock-solid-addevent */
function addEvent(obj, type, fn) {
if (obj.addEventListener) {
obj.addEventListener(type, fn, false);
EventCache.add(obj, type, fn);
}
else if (obj.attachEvent) {
obj["e" + type + fn] = fn;
obj[type + fn] = function() {
obj["e" + type + fn](window.event);
}
obj.attachEvent("on" + type, obj[type + fn]);
EventCache.add(obj, type, fn);
}
else {
obj["on" + type] = obj["e" + type + fn];
}
}
var EventCache = function() {
var listEvents = [];
return {
listEvents: listEvents,
add: function(node, sEventName, fHandler) {
listEvents.push(arguments);
},
flush: function() {
var i, item;
for (i = listEvents.length - 1; i >= 0; i = i - 1) {
item = listEvents[i];
if (item[0].removeEventListener) {
item[0].removeEventListener(item[1], item[2], item[3]);
};
if (item[1].substring(0, 2) != "on") {
item[1] = "on" + item[1];
};
if (item[0].detachEvent) {
item[0].detachEvent(item[1], item[2]);
};
item[0][item[1]] = null;
};
}
};
}();
/* http://www.dustindiaz.com/getelementsbyclass */
function getElementsByClass(searchClass,node,tag) {
var classElements = new Array();
if ( node == null )
node = document;
if ( tag == null )
tag = '*';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
}
var statuss=getElementsByClass('status-infos');
for (var i=0;i<statuss.length;i++){
addEvent(statuss[i], 'click', function (e) {
var xx = this.getAttribute('data-xx');
alert(xx);
return false;
});
}
Demo | Demo Source
Use an addEventListener or attachEvent (IE).
var elements = document.getElementByClassName('status-infos');
for(var i=0; i < elements.length; i++) {
elements[i].addEventListener('click', function(e) {
...
});
}
More info
I build a prototype that handle pages, I successfully add (push), but can get the data, I failed:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
Here the javascript page handler:
var Pages = new Array();
PageContainer = function () //constructor for the proxy
{
// this._baseURL = url;
};
PageContainer.prototype =
{
AddPage: function (data) {
if (data == null) return;
Pages.push({ PageID: data.PageID, SegmentID: data.SegmentID });
},
GetPage: function (PageID) {
alert('getPage('+PageID+')=' + JSON.stringify(Pages));
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
var dt = { PageID: Pages[foundImageIndex].PageID, SegmentID: Pages[foundImageIndex].SegmentID };
return dt;
}
};
I call from other js as following:
var gPageContainer = new PageContainer();
for (var i = 0; i < SegStruct.SegmentsCount; i++) {
var segRClass = //get from webservice
gPageContainer.AddPage({ PageID: i, SegmentID: segRClass.SegmentID });
}
I trying to call: gPageContainer.GetPage(1); but it failed in GetPage: function (PageID) it returns -1 in:
var foundImageIndex = Pages.indexFirst(function (item) { if (item.PageID == PageID) return true; });
foundImageIndex always -1
why?
Simply add the following before the constructor:
if (typeof Array.prototype.indexFirst == 'undefined') {
Array.prototype.indexFirst = function (validator) {
for (var i = 0; i <= this.length - 1; i++) {
if (validator(this[i])) {
return i;
}
}
return -1;
};
}