I have a array type in Javascript:
var type=[0,1,2,3,4,5];
The corresponding key value pair collection is actually like this;
[{0:'Pointer'},{1:'Line'},{2:'Oval'},{3:'Rectangle'},{4:'Ellipse'},{5,'Star'}]
My .dust file displays the {type} mark, how should I display their corresponding values?
You may use a custom filter. The approximate implementation would be:
var mapping = {
'0':'Pointer',
'1':'Line',
'2':'Oval',
'3':'Rectangle',
'4':'Ellipse',
'5':'Star'
};
dust.filters['typeFilter'] = function(value) {
return mapping[value] || '';
}
And in you template: {type|typeFilter}
It's a bit simpler to store the mapping in an object than array. For you array version it would be like:
var mapping = [{0:'Pointer'},{1:'Line'},{2:'Oval'},{3:'Rectangle'},{4:'Ellipse'},{5:'Star'}];
dust.filters['typeFilter'] = function(value) {
var typeId = parseInt(value);
for(var len = mapping.length - 1; len >=0; len--) {
if (mapping[len].hasOwnProperty(typeId)) {
return mapping[len][typeId];
}
}
return '';
}
A bit more information here
Related
difficult one to explain.
var options = {
container: node,
pin: {
size: [50, 50],
anchor: 0,
animation: 0
}
}
Let's use the above Object as an example. I want to loop through the dataset from an HTMLElement and update the above values using the dataset values. This removed the need to manually check if the dataset value exists and then replace the value.
What I have got so far:
(function() {
for( const data in node.dataset ) {
// First remove the 'map' as this isn't required, then split any values with multiple capitals,
// as these corrospond to multilevel object values.
var key = (data.replace("map", "")).split(/(?=[A-Z])/), value = node.dataset[data];
const findOption = function() {
};
// Check that there is a value
if (value !== null) {
const opt = null;
// Find the corresponding default option
}
}
}.call(_));
Here is the HTML with the dataset attributes, this should help everything make more sense:
<div data-map data-map-offset='[10, 10]' data-map-pin-size='[20, 20]'></div>
As you can see above the attribute data-map-pin-size needs to replace the value within the object, but i'm not sure how to reference that object as usually I would either do options.pin.size or options['pin']['size']. But due to this loop not knowing how deep it needs to go I can't always rely on this, I need some kind of callback function right? Which is why I started findOption() however i'm not too sure where to go from there!
Edit:
This is what I have got so far now, however this isn't updating the options object, it's just setting the value of opt.
(function() {
for( const data in node.dataset ) {
// First remove the 'map' as this isn't required, then split any values with multiple capitals,
// as these corrospond to multilevel object values.
var key = (data.replace("map", "")).split(/(?=[A-Z])/), value = node.dataset[data];
// Pin Size
const findOption = function(val) {
return options[val.toLowerCase()];
};
// Check that there is a value
if (value !== null) {
var opt = null;
// Find the corresponding default option
for (var x = 0; key.length > x; x++) {
opt = findOption(key[x]);
}
opt = value;
}
}
console.log(options);
}.call(_));
If you convert your options to this format:
var options = {
container: node,
pinSize: [50, 50],
pinAnchor: 0,
pinAnimation: 0
}
your implementation would be able to be simplified to this:
for (const key in node.dataset) {
const opt = key.replace(/^map(.)/, (match, c) => c.toLowerCase())
options[opt] = JSON.parse(node.dataset[key])
}
assuming you intend to use JSON-compliant values in your HTML data- attributes.
Here I added a recursive function to set the value by finding the specific key on the options object. You can see that for any length of data set attribute the values are getting set properly.
This works with any kind of options object format dynamically.
I added an extra sample as well to demonstrate it.
(function() {
//A function to set the value on a nested object by
//recursively finding the key
function setValue(object, key, value) {
var value;
Object.keys(object).some(function(k) {
if (k === key) {
object[k] = value;
}
if (object[k] && typeof object[k] === 'object') {
setValue(object[k], key, value);
}
});
}
node = document.getElementById("elem");
var options = {
container: node,
pin: {
size: [50, 50],
anchor: 0,
animation: 0,
value: {
xy: [1, 1]
}
}
}
for (const data in node.dataset) {
// First remove the 'map' as this isn't required, then split any values with multiple capitals,
// as these corrospond to multilevel object values.
var keys = (data.replace("map", "")).split(/(?=[A-Z])/),
value = node.dataset[data];
var findOption = function() {
keys.forEach(function(key, index) {
if (index == keys.length - 1) {
setValue(options, key.toLowerCase(), value);
}
})
}();
// Check that there is a value
if (value !== null) {
const opt = null;
// Find the corresponding default option
}
}
console.log(options);
}.call());
<div data-map data-map-offset='[10, 10]' data-map-pin-size='[20, 20]' data-map-pin-value-xy='[0, 5]' id="elem"></div>
I am doing the below to get certain nodes from a treeview followed by getting text from those nodes, filtering text to remove unique and then appending custom image to the duplicate nodes.
For this I am having to loop 4 times. Is there is a simpler way of doing this? I am worried about it's performance for large amount of data.
//Append duplicate item nodes with custom icon
function addRemoveForDuplicateItems() {
var treeView = $('#MyTree').data('t-TreeView li.t-item');
var myNodes = $("span.my-node", treeView);
var myNames = [];
$(myNodes).each(function () {
myNames.push($(this).text());
});
var duplicateItems = getDuplicateItems(myNames);
$(myNodes).each(function () {
if (duplicateItems.indexOf($(this).text()) > -1) {
$(this).parent().append(("<span class='remove'></span>"));
}
});
}
//Get all duplicate items removing unique ones
//Input [1,2,3,3,2,2,4,5,6,7,7,7,7] output [2,3,3,2,2,7,7,7,7]
function getDuplicateItems(myNames) {
var duplicateItems = [], itemOccurance = {};
for (var i = 0; i < myNames.length; i++) {
var dept = myNames[i];
itemOccurance[dept] = itemOccurance[dept] >= 1 ? itemOccurance[dept] + 1 : 1;
}
for (var item in itemOccurance) {
if (itemOccurance[item] > 1)
duplicateItems.push(item);
}
return duplicateItems;
}
If I understand correctly, the whole point here is simply to mark duplicates, right? You ought to be able to do this in two simpler passes:
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node
myNodes.each(function () {
var name = $(this).text();
if (seen[name] === SEEN_DUPE) {
$(this).parent().append("<span class='remove'></span>");
}
});
If you're actually concerned about performance, note that iterating over DOM elements is much more of a performance concern than iterating over an in-memory array. The $(myNodes).each(...) calls are likely significantly more expensive than iteration over a comparable array of the same length. You can gain some efficiencies from this, by running the second pass over an array and only accessing DOM nodes as necessary:
var names = [];
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
names.push(name);
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node only for dupes
names.forEach(function(name, index) {
if (seen[name] === SEEN_DUPE) {
myNodes.eq(index).parent()
.append("<span class='remove'></span>");
}
});
The approach of this code is to go through the list, using the property name to indicate whether the value is in the array. After execution, itemOccurance will have a list of all the names, no duplicates.
var i, dept, itemOccurance = {};
for (i = 0; i < myNames.length; i++) {
dept = myNames[i];
if (typeof itemOccurance[dept] == undefined) {
itemOccurance[dept] = true;
}
}
If you must keep getDuplicateItems() as a separate, generic function, then the first loop (from myNodes to myNames) and last loop (iterate myNodes again to add the span) would be unavoidable. But I am curious. According to your code, duplicateItems can just be a set! This would help simplify the 2 loops inside getDuplicateItems(). #user2182349's answer just needs one modification: add a return, e.g. return Object.keys(itemOccurance).
If you're only concerned with ascertaining duplication and not particularly concerned about the exact number of occurrences then you could consider refactoring your getDuplicateItems() function like so:
function getDuplicateItems(myNames) {
var duplicateItems = [], clonedArray = myNames.concat(), i, dept;
for(i=0;i<clonedArray.length;i+=1){
dept = clonedArray[i];
if(clonedArray.indexOf(dept) !== clonedArray.lastIndexOf(dept)){
if(duplicateItems.indexOf(dept) === -1){
duplicateItems.push(dept);
}
/* Remove duplicate found by lastIndexOf, since we've already established that it's a duplicate */
clonedArray.splice(clonedArray.lastIndexOf(dept), 1);
}
}
return duplicateItems;
}
Is it possible to exclude a property from search using ng-model and ng-repeat?
You can specify a property and its values like this : ng-model="search.property", but what if I want the search to match all the values except the values in one specific property? Does Angular have any solution for this?
This is the filter I am using now :
angular.module('app')
.filter("multiText", function ($filter) {
return function (inputArray, searchText) {
var wordArray = searchText ? searchText.toLowerCase().split(/\s+/) : [];
var wordCount = wordArray.length;
for (var i = 0; i < wordCount; i++) {
inputArray = $filter('filter')(inputArray, wordArray[i]);
}
return inputArray;
};
});
i need to retrieve a value from an URL in JS, my problem is in this url, the element is repeated at least twice with different value. What i need is the last one.
Example :
http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3
and what i want is "random3" and NOT "random1"
I've tried url.match(/.(\&|\?)element1=(.?)\&/)[2];
But it always gives me the first one :(
I don't have the possibility to change how the url is written as this is for a browser extension.
var ws = "http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3",
input = ws.split("?")[1].split("&"),
dataset = {},
val_to_find = "element1";
for ( var item in input){
var d = input[item].split("=");
if (!dataset[d[0]]){ dataset[d[0]] = new Array(); dataset[d[0]].push(d[1]); }
else{
dataset[d[0]].push(d[1]);
}
}
console.log("item: ", dataset[val_to_find][dataset[val_to_find].length -1]);
return dataset[val_to_find][dataset[val_to_find].length -1];
http://jsfiddle.net/wMuHW/
Take the minimum value (other than -1) from urlString.lastIndexOf("&element1=") and urlString.lastIndexOf("?element1="), then use urlString.substring.
Or alternately, split the string up:
var parts = urlString.split(/[?&]/);
...which will give you:
[
"http://randomsite.com/index.php",
"element1=random1",
"element2=random2",
"element1=random3"
]
...then start looping from the end of the array finding the first entry that starts with element= and grabbing the bit after the = (again with substring).
You could;
for (var result, match, re = /[&?]element1=(.+?)(\&|$)/g; match = re.exec(url);) {
result = match[1];
}
alert(result);
Id try keeping a nested array of duplicate elements
function parseQueryString() {
var elements = {},
query = window.location.search.substring(1),
vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('='),
key = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);
if (elements.hasOwnProperty(key)) {
elements[key].push(value);
}
else {
elements[key] = [value];
}
}
}
Used on: www.example.com?element1=hello&element2=test&element1=more
Would give you the object:
{
element1: [
"hello",
"more"
],
element2:[
"test"
]
}
When i create associate array in javascript, i got a problem like that.
I want to get the value by using field name as key, but i just only got undefined.
What should i do to get value by key or which way is good approach for it.
Here is my code
function getFields(pVal){
var tmpObj = {};
str = pVal.split(",");
for(i=0;i<str.length;i++){
tmpVal = str[i].split(":");
tmpObj[tmpVal[0]] = tmpVal[1];
}
return tmpObj;
}
function JustTest(){
var fields = {};
fields = getFields("'Code':'PRJ001','Name':'Project 01'");
alert(fields['Code']);
}
Because the key is 'Code', not Code, note the single quote ', you need do alert(fields["'Code'"]);
PS: Please add ; at the end of statement, it is bad practice to omit them.
I have re-factor the code, just try this:
function getFields(pVal) {
var tmpObj = {};
var str = pVal.split(",");
for (var i = 0; i < str.length; i++) {
var tmpVal = str[i].split(":");
tmpObj[tmpVal[0]] = tmpVal[1];
}
return tmpObj;
}
function JustTest() {
var fields = { };
fields = getFields("'Code':'PRJ001','Name':'Project 01'");
alert(fields["'Code'"]);
}
if you have question please comment below about code, thanks