Related
I am trying to create shortcuts for the list of posts on javascript.
I have the shortcut and posts with categories.
I need to filter the posts by shortcut.
Only a strict comparison:
['Boxer', 'Terrier'] !== ['Boxer', 'Terrier', 'Bulldog']
['Boxer'] !== ['Boxer', 'Terrier', 'Bulldog']
['Boxer', 'Terrier'] === ['Boxer', 'Terrier']
['Boxer', 'Terrier'] === ['Terrier', 'Boxer']
['Boxer'] === ['Boxer']
I came to this option, but I think it's poor quality code:
var allPosts = [
{
categories: [
['cats'],
['Cymric', 'Persian']
],
id: 1,
title: 'Cats',
message: 'Cymric, Persian'
},
{
categories: [
['dogs'],
['Boxer', 'Terrier']
],
id: 2,
title: 'Dogs',
message: 'Boxer, Terrier'
},
...
]
var shortcutCategories = [
['dogs'],
['Boxer', 'Terrier']
]
var displayedPosts = [];
var displayedPostsId = [];
shortcutCategories.forEach(function (shortcutSetOfCategory) {
if (shortcutSetOfCategory.length > 1) {
var internalCompare = false;
allPosts.forEach(function (post) {
post.categories.forEach(function (postSetOfCategory) {
if (postSetOfCategory.length > 1) {
shortcutSetOfCategory.every(function (shortcutCategory) {
internalCompare = postSetOfCategory.includes(shortcutCategory);
return internalCompare;
});
if (!internalCompare) {
return;
}
displayedPostsId.push(post.id);
}
});
});
} else {
allPosts.forEach(function (post) {
post.categories.forEach(function (postSetOfCategory) {
if (postSetOfCategory.length === 1) {
if (shortcutSetOfCategory[0] === postSetOfCategory[0]) {
displayedPostsId.push(post.id);
}
}
});
});
}
});
allPosts.forEach(function (post) {
var count = 0;
displayedPostsId.forEach(function (id) {
if (id === post.id)
count++;
});
if (shortcutCategories.length === count) {
displayedPosts.push(post);
}
});
I think you can use JSON.stringify to compare the 2-D array
JSON.stringify(['Boxer', 'Terrier']) === JSON.stringify(['Boxer', 'Terrier']);
I am a newbie to HTML/Javascript Language.
I am trying to implement quaggaJS barcode scanner Using the live-stream into my HTML page. its working fine but what i want is to get the result on input field.
Below is my input field:
<input class="form-control" type="number" name="id" required autofocus>
This is live_w_locator.js file from quaggaJS:
$(function() {
var resultCollector = Quagga.ResultCollector.create({
capture: true,
capacity: 20,
blacklist: [{
code: "WIWV8ETQZ1", format: "code_93"
}, {
code: "EH3C-%GU23RK3", format: "code_93"
}, {
code: "O308SIHQOXN5SA/PJ", format: "code_93"
}, {
code: "DG7Q$TV8JQ/EN", format: "code_93"
}, {
code: "VOFD1DB5A.1F6QU", format: "code_93"
}, {
code: "4SO64P4X8 U4YUU1T-", format: "code_93"
}],
filter: function(codeResult) {
// only store results which match this constraint
// e.g.: codeResult
return true;
}
});
var App = {
init: function() {
var self = this;
Quagga.init(this.state, function(err) {
if (err) {
return self.handleError(err);
}
//Quagga.registerResultCollector(resultCollector);
App.attachListeners();
App.checkCapabilities();
Quagga.start();
});
},
handleError: function(err) {
console.log(err);
},
checkCapabilities: function() {
var track = Quagga.CameraAccess.getActiveTrack();
var capabilities = {};
if (typeof track.getCapabilities === 'function') {
capabilities = track.getCapabilities();
}
this.applySettingsVisibility('zoom', capabilities.zoom);
this.applySettingsVisibility('torch', capabilities.torch);
},
updateOptionsForMediaRange: function(node, range) {
console.log('updateOptionsForMediaRange', node, range);
var NUM_STEPS = 6;
var stepSize = (range.max - range.min) / NUM_STEPS;
var option;
var value;
while (node.firstChild) {
node.removeChild(node.firstChild);
}
for (var i = 0; i <= NUM_STEPS; i++) {
value = range.min + (stepSize * i);
option = document.createElement('option');
option.value = value;
option.innerHTML = value;
node.appendChild(option);
}
},
applySettingsVisibility: function(setting, capability) {
// depending on type of capability
if (typeof capability === 'boolean') {
var node = document.querySelector('input[name="settings_' + setting + '"]');
if (node) {
node.parentNode.style.display = capability ? 'block' : 'none';
}
return;
}
if (window.MediaSettingsRange && capability instanceof window.MediaSettingsRange) {
var node = document.querySelector('select[name="settings_' + setting + '"]');
if (node) {
this.updateOptionsForMediaRange(node, capability);
node.parentNode.style.display = 'block';
}
return;
}
},
initCameraSelection: function(){
var streamLabel = Quagga.CameraAccess.getActiveStreamLabel();
return Quagga.CameraAccess.enumerateVideoDevices()
.then(function(devices) {
function pruneText(text) {
return text.length > 30 ? text.substr(0, 30) : text;
}
var $deviceSelection = document.getElementById("deviceSelection");
while ($deviceSelection.firstChild) {
$deviceSelection.removeChild($deviceSelection.firstChild);
}
devices.forEach(function(device) {
var $option = document.createElement("option");
$option.value = device.deviceId || device.id;
$option.appendChild(document.createTextNode(pruneText(device.label || device.deviceId || device.id)));
$option.selected = streamLabel === device.label;
$deviceSelection.appendChild($option);
});
});
},
attachListeners: function() {
var self = this;
self.initCameraSelection();
$(".controls").on("click", "button.stop", function(e) {
e.preventDefault();
Quagga.stop();
self._printCollectedResults();
});
$(".controls .reader-config-group").on("change", "input, select", function(e) {
e.preventDefault();
var $target = $(e.target),
value = $target.attr("type") === "checkbox" ? $target.prop("checked") : $target.val(),
name = $target.attr("name"),
state = self._convertNameToState(name);
console.log("Value of "+ state + " changed to " + value);
self.setState(state, value);
});
},
_printCollectedResults: function() {
var results = resultCollector.getResults(),
$ul = $("#result_strip ul.collector");
results.forEach(function(result) {
var $li = $('<li><div class="thumbnail"><div class="imgWrapper"><img /></div><div class="caption"><h4 class="code"></h4></div></div></li>');
$li.find("img").attr("src", result.frame);
$li.find("h4.code").html(result.codeResult.code + " (" + result.codeResult.format + ")");
$ul.prepend($li);
});
},
_accessByPath: function(obj, path, val) {
var parts = path.split('.'),
depth = parts.length,
setter = (typeof val !== "undefined") ? true : false;
return parts.reduce(function(o, key, i) {
if (setter && (i + 1) === depth) {
if (typeof o[key] === "object" && typeof val === "object") {
Object.assign(o[key], val);
} else {
o[key] = val;
}
}
return key in o ? o[key] : {};
}, obj);
},
_convertNameToState: function(name) {
return name.replace("_", ".").split("-").reduce(function(result, value) {
return result + value.charAt(0).toUpperCase() + value.substring(1);
});
},
detachListeners: function() {
$(".controls").off("click", "button.stop");
$(".controls .reader-config-group").off("change", "input, select");
},
applySetting: function(setting, value) {
var track = Quagga.CameraAccess.getActiveTrack();
if (track && typeof track.getCapabilities === 'function') {
switch (setting) {
case 'zoom':
return track.applyConstraints({advanced: [{zoom: parseFloat(value)}]});
case 'torch':
return track.applyConstraints({advanced: [{torch: !!value}]});
}
}
},
setState: function(path, value) {
var self = this;
if (typeof self._accessByPath(self.inputMapper, path) === "function") {
value = self._accessByPath(self.inputMapper, path)(value);
}
if (path.startsWith('settings.')) {
var setting = path.substring(9);
return self.applySetting(setting, value);
}
self._accessByPath(self.state, path, value);
console.log(JSON.stringify(self.state));
App.detachListeners();
Quagga.stop();
App.init();
},
inputMapper: {
inputStream: {
constraints: function(value){
if (/^(\d+)x(\d+)$/.test(value)) {
var values = value.split('x');
return {
width: {min: parseInt(values[0])},
height: {min: parseInt(values[1])}
};
}
return {
deviceId: value
};
}
},
numOfWorkers: function(value) {
return parseInt(value);
},
decoder: {
readers: function(value) {
if (value === 'ean_extended') {
return [{
format: "ean_reader",
config: {
supplements: [
'ean_5_reader', 'ean_2_reader'
]
}
}];
}
return [{
format: value + "_reader",
config: {}
}];
}
}
},
state: {
inputStream: {
type : "LiveStream",
constraints: {
width: {min: 640},
height: {min: 480},
facingMode: "environment",
aspectRatio: {min: 1, max: 2}
}
},
locator: {
patchSize: "medium",
halfSample: true
},
numOfWorkers: 2,
frequency: 10,
decoder: {
readers : [{
format: "code_128_reader",
config: {}
}]
},
locate: true
},
lastResult : null
};
App.init();
Quagga.onProcessed(function(result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
result.boxes.filter(function (box) {
return box !== result.box;
}).forEach(function (box) {
Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: "green", lineWidth: 2});
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: "#00F", lineWidth: 2});
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, {x: 'x', y: 'y'}, drawingCtx, {color: 'red', lineWidth: 3});
}
}
});
Quagga.onDetected(function(result) {
var code = result.codeResult.code;
if (App.lastResult !== code) {
App.lastResult = code;
var $node = null, canvas = Quagga.canvas.dom.image;
$node = $('<li><div class="thumbnail"><div class="imgWrapper"><img /></div><div class="caption"><h4 class="code"></h4></div></div></li>');
$node.find("img").attr("src", canvas.toDataURL());
$node.find("h4.code").html(code);
$("#result_strip ul.thumbnails").prepend($node);
}
});
});
Appreciate your help...Thank You
You can get the reference of your input control and set its value to the code variable in the onDetected code block.
Quagga.onDetected(function(result) {
var code = result.codeResult.code;
document.getElementById('MyInput').value = code;
});
Recently I was working on a project with this extension and I have noticed that when I select "FIELD" option and enter a value everything works fine. But after I delete value from field and push enter whole app crash because of undefined value. Maybe someone could help me with code how to avoid this annoying crash?
Thx in advance!
Here is whole code.
/*global define*/
define(["qlik"], function(qlik) {
'use strict';
var BTN_SELECTED = 'qui-button-selected',
BTN = 'qui-button',
SELECT = 'qui-select',
INPUT = 'qui-input';
function createVariable(name) {
var app = qlik.currApp();
//from 2.1: check if variable exists
if (app.variable.getByName) {
app.variable.getByName(name).then(function() {
//variable already exist
}, function() {
//create variable
app.variable.create(name);
});
} else {
//create variable - ignore errors
app.variable.create(name);
}
}
function createElement(tag, cls, html) {
var el = document.createElement(tag);
if (cls) {
el.className = cls;
}
if (html !== undefined) {
el.innerHTML = html;
}
return el;
}
return {
initialProperties: {
variableValue: {},
variableName: "",
render: "f",
defaultValue: 0,
alternatives: []
},
definition: {
type: "items",
component: "accordion",
items: {
settings: {
uses: "settings",
items: {
variable: {
type: "items",
label: "Variable",
items: {
name: {
ref: "variableName",
label: "Name",
type: "string",
change: function(data) {
createVariable(data.variableName);
data.variableValue.qStringExpression = '=' + data.variableName;
}
},
render: {
type: "string",
component: "dropdown",
label: "Render as",
ref: "render",
options: [{
value: "b",
label: "Button"
}, {
value: "s",
label: "Select"
}, {
value: "f",
label: "Field"
}, {
value: "l",
label: "Slider"
}],
defaultValue: "f"
},
emptyVal: {
ref: "emptyVal",
label: "default(when empty)",
type: "string",
defaultValue: 0
},
alternatives: {
type: "array",
ref: "alternatives",
label: "Alternatives",
itemTitleRef: "label",
allowAdd: true,
allowRemove: true,
addTranslation: "Add Alternative",
items: {
value: {
type: "string",
ref: "value",
label: "Value"
},
label: {
type: "string",
ref: "label",
label: "Label",
expression: "optional"
}
},
show: function(data) {
return data.render === "b" || data.render === "s";
}
},
min: {
ref: "min",
label: "Min",
type: "number",
defaultValue: 0,
show: function(data) {
return data.render === "l";
}
},
max: {
ref: "max",
label: "Max",
type: "number",
defaultValue: 100,
show: function(data) {
return data.render === "l";
}
},
step: {
ref: "step",
label: "Step",
type: "number",
defaultValue: 1,
show: function(data) {
return data.render === "l";
}
}
}
}
}
}
}
},
paint: function($element, layout) {
var wrapper = createElement('div'),
ext = this;
empty = layout.emptyVal;
if (layout.render === 'b') {
layout.alternatives.forEach(function(alt) {
var clazz = alt.value === layout.variableValue ? BTN_SELECTED : BTN;
var btn = createElement('button', clazz, alt.label);
btn.onclick = function() {
qlik.currApp(ext).variable.setContent(layout.variableName, alt.value);
}
wrapper.appendChild(btn);
});
} else if (layout.render === 's') {
var sel = createElement('select', SELECT);
layout.alternatives.forEach(function(alt) {
var opt = createElement('option', undefined, alt.label);
opt.value = alt.value;
opt.selected = alt.value === layout.variableValue;
sel.appendChild(opt);
});
sel.onchange = function() {
qlik.currApp(ext).variable.setContent(layout.variableName, this.value);
}
wrapper.appendChild(sel);
} else if (layout.render === 'l') {
var range = createElement('input');
range.type = 'range';
range.min = layout.min || 0;
range.max = layout.max || 100;
range.step = layout.step || 1;
range.value = layout.variableValue;
range.title = layout.variableValue;
range.style.width = '98%';
range.onchange = function() {
qlik.currApp(ext).variable.setContent(layout.variableName, this.value);
}
wrapper.appendChild(range);
} else {
var fld = createElement('input', INPUT);
fld.type = 'number';
fld.value = layout.variableValue;
fld.onchange = function () {
if (this.value != "undifined") {
qlik.currApp(ext).variable.setContent(layout.variableName, this.value);
} else {
qlik.currApp(ext).variable.setContent(layout.variableName, 0);
}
}
wrapper.appendChild(fld);
}
var elem = $element[0];
if (elem.childNodes.length === 0) {
elem.appendChild(wrapper);
} else {
elem.replaceChild(wrapper, elem.childNodes[0]);
}
}
};
});
if (this.value != "undifined") {
Here, you are comparing value to the string "undifined" (which is also mistyped).
It seems you want to compare to the value undefined:
if (this.value !== undefined) {
or check the data type of value:
if (typeof this.value != "undefined") {
I want to display my custom RSS feed as a horizontal list. I am using a responsive template and embedding my feeds into that template. I believe that my JavaScript is not separating each RSS post into a separate list item like I thought it would.
(function($) {
"use strict";
var RSS = function(target, url, options, callback) {
this.target = target
this.url = url
this.html = []
this.effectQueue = []
this.options = $.extend({
ssl: false,
limit: null,
key: null,
layoutTemplate: '<ul style="display:inline-block;">{entries}</ul>',
entryTemplate: '<li><div class="title">{title}</div><br /><author>{author}</author><img src="{teaserImageUrl}"></img><date>{date}</date><br />{shortBodyPlain}</li>',
tokens: {
},
outputMode: 'json',
dateFormat: 'MMM Do, YYYY',
effect: 'show',
offsetStart: false,
offsetEnd: false,
error: function() {
console.log("jQuery RSS: url doesn't link to RSS-Feed");
},
onData: function(){},
success: function(){}
}, options || {})
this.callback = callback || this.options.success
}
RSS.htmlTags = ["doctype", "html", "head", "title", "base", "link", "meta", "style", "script", "noscript", "body", "article", "nav", "aside", "section", "header", "footer", "h1-h6", "hgroup", "address", "p", "hr", "pre", "blockquote", "ol", "ul", "li", "dl", "dt", "dd", "figure", "figcaption", "div", "table", "caption", "thead", "tbody", "tfoot", "tr", "th", "td", "col", "colgroup", "form", "fieldset", "legend", "label", "input", "button", "select", "datalist", "optgroup", "option", "textarea", "keygen", "output", "progress", "meter", "details", "summary", "command", "menu", "del", "ins", "img", "iframe", "embed", "object", "param", "video", "audio", "source", "canvas", "track", "map", "area", "a", "em", "strong", "i", "b", "u", "s", "small", "abbr", "q", "cite", "dfn", "sub", "sup", "time", "code", "kbd", "samp", "var", "mark", "bdi", "bdo", "ruby", "rt", "rp", "span", "br", "wbr"]
RSS.prototype.load = function(callback) {
var apiProtocol = "http" + (this.options.ssl ? "s" : "")
, apiHost = apiProtocol + "://ajax.googleapis.com/ajax/services/feed/load"
, apiUrl = apiHost + "?v=1.0&output=" + this.options.outputMode + "&callback=?&q=" + encodeURIComponent(this.url)
// set limit to offsetEnd if offset has been set
if(this.options.offsetStart && this.options.offsetEnd) this.options.limit = this.options.offsetEnd;
if (this.options.limit != null) apiUrl += "&num=" + this.options.limit;
if (this.options.key != null) apiUrl += "&key=" + this.options.key;
$.getJSON(apiUrl, callback)
}
RSS.prototype.render = function() {
var self = this
this.load(function(data) {
try {
self.feed = data.responseData.feed
self.entries = data.responseData.feed.entries
} catch(e) {
self.entries = []
self.feed = null
return self.options.error.call(self)
}
var html = self.generateHTMLForEntries()
self.target.append(html.layout)
if (html.entries.length !== 0) {
$.isFunction(self.options.onData) && self.options.onData.call(self);
self.appendEntriesAndApplyEffects($("entries", html.layout), html.entries);
}
if (self.effectQueue.length > 0) {
self.executeEffectQueue(self.callback)
} else {
$.isFunction(self.callback) && self.callback.call(self);
}
})
}
RSS.prototype.appendEntriesAndApplyEffects = function(target, entries) {
var self = this
$.each(entries, function(idx, entry) {
var $html = self.wrapContent(entry)
if(self.options.effect === 'show') {
target.before($html)
} else {
$html.css({ display: 'none' })
target.before($html)
self.applyEffect($html, self.options.effect)
}
})
target.remove()
}
RSS.prototype.generateHTMLForEntries = function() {
var self = this
, result = {
entries: [],
layout: null
}
$(this.entries).each(function() {
var entry = this,
offsetStart = self.options.offsetStart,
offsetEnd = self.options.offsetEnd;
// offset required
if(offsetStart && offsetEnd) {
if(index >= offsetStart && index <= offsetEnd) {
if(self.isRelevant(entry, result.entries)) {
var evaluatedString = self.evaluateStringForEntry(self.options.entryTemplate, entry)
result.entries.push(evaluatedString)
}
}
}else{
// no offset
if(self.isRelevant(entry, result.entries)) {
var evaluatedString = self.evaluateStringForEntry(self.options.entryTemplate, entry)
result.entries.push(evaluatedString)
}
}
})
if(!!this.options.entryTemplate) {
// we have an entryTemplate
result.layout = this.wrapContent(this.options.layoutTemplate.replace("{entries}", "<entries></entries>"))
} else {
// no entryTemplate available
result.layout = this.wrapContent("<div><entries></entries></div>")
}
return result
}
RSS.prototype.wrapContent = function(content) {
if($.trim(content).indexOf('<') !== 0) {
// the content has no html => create a surrounding div
return $("<div>" + content + "</div>")
} else {
// the content has html => don't touch it
return $(content)
}
}
RSS.prototype.applyEffect = function($element, effect, callback) {
var self = this
switch(effect) {
case 'slide':
$element.slideDown('slow', callback)
break
case 'slideFast':
$element.slideDown(callback)
break
case 'slideSynced':
self.effectQueue.push({ element: $element, effect: 'slide' })
break
case 'slideFastSynced':
self.effectQueue.push({ element: $element, effect: 'slideFast' })
break
}
}
RSS.prototype.executeEffectQueue = function(callback) {
var self = this
this.effectQueue.reverse()
var executeEffectQueueItem = function() {
var item = self.effectQueue.pop()
if(item) {
self.applyEffect(item.element, item.effect, executeEffectQueueItem)
} else {
callback && callback()
}
}
executeEffectQueueItem()
}
RSS.prototype.evaluateStringForEntry = function(string, entry) {
var result = string
, self = this
$(string.match(/(\{.*?\})/g)).each(function() {
var token = this.toString()
result = result.replace(token, self.getValueForToken(token, entry))
})
return result
}
RSS.prototype.isRelevant = function(entry, entries) {
var tokenMap = this.getTokenMap(entry)
if(this.options.filter) {
if(this.options.filterLimit && (this.options.filterLimit == entries.length)) {
return false
} else {
return this.options.filter(entry, tokenMap)
}
} else {
return true
}
}
RSS.prototype.getTokenMap = function(entry) {
if (!this.feedTokens) {
var feed = JSON.parse(JSON.stringify(this.feed))
delete feed.entries
this.feedTokens = feed
}
return $.extend({
feed: this.feedTokens,
url: entry.link,
author: entry.author,
date: moment(entry.publishedDate).format(this.options.dateFormat),
title: entry.title,
body: entry.content,
shortBody: entry.contentSnippet,
bodyPlain: (function(entry) {
var result = entry.content
.replace(/<script[\\r\\\s\S]*<\/script>/mgi, '')
.replace(/<\/?[^>]+>/gi, '')
for(var i = 0; i < RSS.htmlTags.length; i++) {
result = result.replace(new RegExp('<' + RSS.htmlTags[i], 'gi'), '')
}
return result
})(entry),
shortBodyPlain: entry.contentSnippet.replace(/<\/?[^>]+>/gi, ''),
//shortBodyPlain: entry.contentSnippet.replace("-- Delivered by Feed43 service", ""),
shortBodyPlain: entry.contentSnippet.replace("369gopee", "<author>").replace("321gopee", "</author><br />"),
index: $.inArray(entry, this.entries),
totalEntries: this.entries.length,
teaserImage: (function(entry){
try { return entry.content.match(/(<img.*?>)/gi)[0] }
catch(e) { return "" }
})(entry),
teaserImageUrl: (function(entry) {
try { return entry.content.match(/(<img.*?>)/gi)[0].match(/src="(.*?)"/)[1] }
catch(e) { return "" }
})(entry)
}, this.options.tokens)
}
RSS.prototype.getValueForToken = function(_token, entry) {
var tokenMap = this.getTokenMap(entry)
, token = _token.replace(/[\{\}]/g, '')
, result = tokenMap[token]
if(typeof result != 'undefined')
return ((typeof result == 'function') ? result(entry, tokenMap) : result)
else
throw new Error('Unknown token: ' + _token)
}
$.fn.rss = function(url, options, callback) {
new RSS(this, url, options, callback).render()
return this; //implement chaining
}
})(jQuery)
When I view the page source, there is not dynamically created html. How would I display these list items inline?
The feeds appear in HTML as follows:
<script>
jQuery(function($) {
$("#rss-feeds").rss("http://www.feed43.com/channelfireball.xml", {
limit: 15
})
</script>
<div style="border:none;width:100%;height:auto;overflow-y:scroll;
overflow-x:scroll;">
<div class="span2 item">
<div class="item-wrap">
<div class="post_results" id="rss-feeds"></div>
</div>
</div>
</div>
I'm trying to build a Tree Table that is capable of shown/hide their TR childs when clicked (among other things).
I've grab some code from the web to generate easily generate a tree structure. The problem comes trying to set a parent/child relationship with this event. I'm really not used to react so it is hard for me to understand certain things.
This is the data structure:
var data = [
{
id: 1,
label: 'Order 1',
deep: 0,
children: [{
id: 11,
label: 'Cycle November',
deep: 1,
},
{
id: 12,
label: 'Cycle December',
deep: 1,
}]
},
{
id: 2,
label: 'Order 2',
deep: 0,
children: [{
id: 21,
label: 'Cycle January',
deep: 1
}]
},
];
Then i want to click on Parent id 1 and see who their children are.
This is the code that draws the Table:
var TR = React.createClass({
childs: [],
hasParent: function() {
if (this.props.parent) {
return true;
}
else {
return false;
}
},
componentDidMount: function(){
if (this.hasParent()) {
parentKey = this.props.parent.props.keyId.split('-')[1];
thisKey = this.props.keyId.split('-')[0];
if (parentKey == thisKey) {
console.log('I set the child');
this.props.parent.props.childs.push(this);
}
}
},
handleClick: function(event) {
if (this.hasParent()) {
parent = this.props.parent;
console.log('My father is: '+parent.props.keyId);
console.log('Me and my brothers are: ');
parent.props.childs.map(function(child) {
console.log(child.props.keyId);
});
}
else {
console.log('I am: '+this.props.keyId);
console.log('My children are:');
this.props.childs.map(function(child) {
console.log(child.props.keyId);
});
}
},
isShown: function() {
return false;
},
getDefaultProps: function() {
return {
childs: new Array(),
};
},
render: function() {
var iparent = this.props.data.deep*20;
return (
<tr>
<td style={{paddingLeft: iparent+'px'}}>
<span onClick={this.handleClick} >
+ </span>
{this.props.data.label}
</td>
</tr>
);
}
});
var Tree = React.createClass({
render: function() {
var treeItems = [];
parent = null;
var renderTreeItems = function(items, parent) {
if (!items) {
return;
}
for (var i = 0; i < items.length; i++) {
if (items[i].deep == 0) {
var parent_id = items[i].deep;
}
else {
var parent_id = parent.props.data.id;
}
var key = parent_id+'-'+items[i].id;
tr = (
<TR key={key} keyId={key} data={items[i]} parent={parent} >
</TR>
);
treeItems.push(
tr
);
renderTreeItems(items[i].children, tr);
}
};
renderTreeItems(this.props.data);
return (
<table>
{ treeItems }
</table>
);
}
});
And last the HTML to attach the component:
<html>
<body>
<div id="tree"></div>
<script type="text/jsx">
React.render(<Tree data={data}/>, document.body);
</script>
</body>
</html>
The actual problem is that childs (badly written i know...) seems to be shared between all TR instances.
Can someone point what i'm doing wrong and what is the best approach to deal with this?
Simply: i want to hide/show childs clicking on the TR-First TD that "acts" as a parent.
Here is the jsfiddle http://jsfiddle.net/69z2wepo/2731/
I approached the problem from a new perspective using a parent_key on every TR and querying against all the array in search of those objects that have that parent_key, changing it's properties. Now I have the start of a fully functional table tree.
//Won't work below IE9, but totally safe otherwise
!function() {
function _dynamicSortMultiple(attr) {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = _dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
};
}
function _dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
Object.defineProperty(Array.prototype, "sortBy", {
enumerable: false,
writable: true,
value: function() {
return this.sort(_dynamicSortMultiple.apply(null, arguments));
}
});
}();
var TD = React.createClass({
onHandleClick: function(event) {
this.props.onHandleClick(this.props.data.key);
},
render: function() {
var iparent = this.props.data.deep*20;
var icon = "fa-chevron-down";
return (
<td style={{paddingLeft: iparent+'px'}}>
<span onClick={this.onHandleClick} className={"fa "+icon}>
</span>
{this.props.data.label}
</td>
);
}
})
var TR = React.createClass({
onHandleClick: function(TD) {
this.props.onHandleClick(TD);
},
render: function() {
if (this.props.data.isShown) {
return (
<tr>
<TD data={this.props.data} onHandleClick={this.onHandleClick}/>
</tr>
);
}
else {
return (
<tr>
</tr>
);
}
}
});
var List = React.createClass({
render: function() {
var self = this;
var trs = this.props.data.map(function(row) {
var key = row.deep+'-'+row.id;
return (<TR key={key} keyId={key} parentKey={row.parent_key} data={row} onHandleClick={self.props.onHandleClick} />);
});
return (
<table>
{trs}
</table>
);
}
});
var Tree = React.createClass({
handleClick: function(key) {
newState = this.state.data.slice();
for (var i = newState.length - 1; i >= 0; i--) {
var item = newState[i];
if (item.parent_key == key) {
item.isShown = (item.isShown)?false:true;
newState[i] = item;
}
};
this.setState({data: newState});
},
loadFromServer: function() {
var data = [
{
id: 1,
label: 'Order 1',
deep: 0,
key: '0-1',
parent_key: '0',
},
{
id: 11,
label: 'Cycle November',
deep: 1,
key: '0-1-11',
parent_key: '0-1',
},
{
id: 12,
label: 'Cycle December',
deep: 1,
key: '0-1-12',
parent_key: '0-1',
},
{
id: 2,
label: 'Order 2',
deep: 0,
key: '0-2',
parent_key: '0'
},
{
id: 21,
label: 'Cycle January',
deep: 1,
key: '0-2-21',
parent_key: '0-2',
}
];
newState = [];
data.map(function(item) {
item.isShown = (item.deep != 0)?false:true;
newState.push(item);
});
newState.sortBy("key");
this.setState({data:newState});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadFromServer();
},
render: function() {
return (
<div className="Box">
<table className="table table-striped table-hover dataTables-orders" >
<thead>
</thead>
<List data={this.state.data} onHandleClick={this.handleClick} />
</table>
</div>
);
}
});
React.render(<Tree data={data}/>, document.getElementById('tree'));