I have a function that I use to pass over a table field name and its value. Depending on the name of the field, it either returns the contents as a link or it does not.
// Given a field name, check to see if its in our output. If so, return the formatted link
function createLink(field, val) {
var output = {
'ntid': 'https://web.internal/profile/' + val,
'email': 'mailTo:' + val
};
var i, key, keys = Object.keys(output);
for ( i = 0; i < keys.length; ++i ) {
key = keys[i];
if(field.toLowerCase() == key){
return ''+val+'';
}
}
return val;
}
Usage:
createLink('email', 'bob#stuff.com')
// returns bob#stuff.com
This also works for NTID. The issue I am having though is there are some field names that contain my values in the output such as Sup Email or Sup NTID and those are not transformed correctly.
Expected Result:
createLink('sup email', 'bob2#stuff2.com')
// returns bob#stuff.com
The Question:
How can I tweak my function to see if my field exists in the output array at all, even if it's not an exact match?
Change your function to
function createLink(field, val) {
var output = {
'ntid': 'https://web.internal/profile/' + val,
'email': 'mailTo:' + val
};
var i, key, keys = Object.keys(output);
for (i = 0; i < keys.length; ++i) {
key = keys[i];
if ((field.toLowerCase()).includes(key)) {
return '' + val + '';
}
}
return val;
}
console.log(createLink('sup email', 'bob2#stuff2.com') )
Notice the code if ((field.toLowerCase()).includes(key)) {
This will check for your key substring in the string
What you're implementing is the Strategy Pattern. The Strategy Pattern relies on some form of behaviour-switching depending on the inputs to the method. In your case, that switching is based on the first argument.
What you don't want to do is what your questions asks how to do. You don't want to assume every field name in your application which contains "email" or some other string is guaranteed to be an email address, handled by the same strategy.
Create a table of field names and strategies to use for the display of each of these fields; and use an "enum-ish" object as the definition of the strategies.
function create_link(field, val) {
const strategy = create_link.Field_Strategies[field];
if (typeof strategy === 'undefined') {
console.log("Using default strategy");
return val;
}
console.log("Using " + strategy);
switch (strategy) {
case create_link.Strategies.EMAIL:
return '' + val + '';
case create_link.Strategies.NTID:
return '<a href="https://web.internal/profile/' +
val + '" target="_blank">' + val + '</a>';
case create_link.Strategies.SOME_FIELD:
return '<a href="http://example.com/some/path/' +
encodeURIComponent(val) +
'" target="_blank">' + val + '</a>';
}
}
create_link.Strategies = {
EMAIL: "email strategy",
NTID: "ntid strategy",
SOME_FIELD: "somefield strategy"
};
create_link.Field_Strategies = {
"Sup email": create_link.Strategies.EMAIL,
"E-mail": create_link.Strategies.EMAIL,
"Email": create_link.Strategies.EMAIL,
"NTID": create_link.Strategies.NTID,
"Foobar baz": create_link.Strategies.SOME_FIELD
};
console.log(create_link("foo","foofoofoo"));
console.log(create_link("Sup email","supervisor#example.com"));
console.log(create_link("E-mail","foo#example.com"));
console.log(create_link("Email","bar#example.com"));
console.log(create_link("NTID","10983409509734"));
console.log(create_link("Foobar baz","Aleph null"));
You could use String.prototype.indexOf.
The indexOf() method returns the index within the calling String object of the first occurrence of the specified value...Returns -1 if the value is not found.
So your code would then look like:
// Given a field name, check to see if its in our output. If so, return the formatted link
function createLink(field, val) {
var output = {
'ntid': 'https://web.internal/profile/' + val,
'email': 'mailTo:' + val
};
var i, key, keys = Object.keys(output);
for ( i = 0; i < keys.length; ++i ) {
key = keys[i];
if(field.toLowerCase().indexOf(key) >= 0){ //CHANGE HERE
return ''+val+'';
}
}
return val;
}
Related
I found some similar questions, but none helped me.
I have an array, and I am pushing items into it. I want to check if there is already an item then removes and add a new value.
I am doing this in the success of an ajax call,
var taxSplitUp = []; // my array
// ajax call here, in the success
for (var i in data.d) {
var ItemTaxAmt= data.d[i].ItemTaxAmt;
var TaxName = data.d[i].TaxName;
var idx = $.inArray(TaxName, taxSplitUp); // checks if already exist
if (idx == -1) {
var tx1 = '{"' + TaxName + '":"' + parseFloat(ItemTaxAmt).toFixed(2) + '"}';
taxSplitUp.push(tx1);
}
else {
taxSplitUp.splice(idx, 1); // removing
var t1 = taxSplitUp[TaxName]; // selecting the value from array
var tx1 = '{"' + TaxName + '":"' + parseFloat(ItemTaxAmt).toFixed(2) + parseFloat(t1).toFixed(2) + '"}';
taxSplitUp.push(tx1);
}
}
Here if the same key came, then I want to add the values together and want only one in the array, but the checking always returns false and adds another into the array.
please help.
$.inArray wont work with associative array. Try below solution
for (var i in data) {
var ItemTaxAmt= data[i].ItemTaxAmt;
var TaxName = data[i].TaxName;
console.log(TaxName);
$.map(taxSplitUp, function(item, index) {
if (item.TaxName == TaxName) {
item.ItemTaxAmt = ItemTaxAmt;
}else{
taxSplitUp.push({
'TaxName' :TaxName,
'ItemTaxAmt' : ItemTaxAmt
});
}
});
}
console.log(taxSplitUp);
I am constructing a query string in Javascript based on whether a checkbox is checked or not.
Some of the options in the checkboxes are
"Annual"
"Grass"
"Shrub (Evergreen)"
"Shrub (Deciduous)"
I found a function online that updates the url parameter:
function updateUrlParameter(uri, key, value) {
value = value.replace(/\s/g, "%20");
var i = uri.indexOf('#');
var hash = i === -1 ? '' : uri.substr(i);
uri = i === -1 ? uri : uri.substr(0, i);
var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (!value) {
// remove key-value pair if value is empty
uri = uri.replace(new RegExp("([&]?)" + key + "=.*?(&|$)", "i"), '');
if (uri.slice(-1) === '?') {
uri = uri.slice(0, -1);
}
} else {
console.log("value is " + value)
uri = uri + separator + key + "=" + value;
}
return uri + hash;
}
Using the above function, if I check the checkboxes for the above four starting from top down, my query string becomes
?plantType=Annual&plantType=Grass&plantType=Shrub%20(Evergreen)&plantType=Shrub%20(Deciduous
Why is the function ignoring the last ')' in the string? Is there a work around this? I would like to keep the parenthesis in the query string because this will make querying the database easier.
I created a function to iterate through input checkboxes. If they are checked, then use the updateUrlParameter function to update the URI.
function getQueryString() {
var inputsContainerChildren = $('#floatingDivForFilter').children();
var input = document.createElement('input')
var uri = '';
for (var i = 0; i < inputsContainerChildren.length; i++) {
var currChild = inputsContainerChildren[i].firstElementChild;
if (currChild) {
if (currChild.tagName === 'INPUT') {
if (currChild.checked) {
var id = currChild.id;
console.log(uri)
uri = updateUrlParameter(uri, currChild.name, currChild.value);
}
}
}
}
console.log(uri);
}
The photo below shows a snapshot of the URL produced. I can't figure out why the last ')' is chopped off.
url photo
The issue you are seeing is just the Chrome developer tools trying to be too clever.
When logging the url to the console, Chrome will not recognize the full url as a link but exclude the closing ")". They probably do that because it will be very common that people write an url in braces and it is not expected that the closing brace is part of the url.
Since this is only an issue of the developer tools, you can ignore the issue. It will not affect the runtime behaviour of your code.
The issue will be solved when you correctly escape special characters in the parameters (as you should do anyway):
function updateUrlParameter(uri, key, value) {
// removed because escape will do that
// value = value.replace(/\s/g, "%20");
var i = uri.indexOf('#');
var hash = i === -1 ? '' : uri.substr(i);
uri = i === -1 ? uri : uri.substr(0, i);
var separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (!value) {
// remove key-value pair if value is empty
uri = uri.replace(new RegExp("([&]?)" + key + "=.*?(&|$)", "i"), '');
if (uri.slice(-1) === '?') {
uri = uri.slice(0, -1);
}
} else {
console.log("value is " + value)
// Use escape on key and value
uri = uri + separator + escape(key) + "=" + escape(value);
}
return uri + hash;
}
let s = "http://chrome.is.too.clever/";
s = updateUrlParameter(s, "plantType", "Annual");
s = updateUrlParameter(s, "plantType", "Grass");
s = updateUrlParameter(s, "plantType", "Shrub (Evergreen)");
s = updateUrlParameter(s, "plantType", "Shrub (Deciduous)");
console.log(s);
Fiddle
Instead of using a regular expression, just convert the params to an object, modify said object, and convert it back into params.
var url = 'https://x.y?plantType=Annual&plantType=Grass&plantType=Shrub%20(Evergreen)&plantType=Shrub%20(Deciduous)';
function updateUrlParameter(uri, key, value) {
let url = new URL(uri), object = deserializeQuery(url.search); // params to obj
object[key] = value; // modify obj
return url.origin + '?' + serializeQuery(object); // obj to url + params
}
console.log(updateUrlParameter(url, 'plantType', [ 'Pine', 'Palm', 'Rose (Red)' ]));
/** ======= Serialization / Deserialization functions below ======== */
// https://stackoverflow.com/a/47517503/1762224
function deserializeQuery(queryString, queryKey) {
let query = {}, pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('='), key = decodeURIComponent(pair[0]), value = decodeURIComponent(pair[1] || '');
value = (value.indexOf(',') === -1 ? value : value.split(','));
query[key] = query[key] ? (query[key].constructor === Array ? query[key].concat(value) : [query[key], value]) : value;
}
return typeof queryKey === 'undefined' ? query : query[queryKey];
}
// https://stackoverflow.com/a/53528203/1762224
function serializeQuery(params, keys = [], isArray = false) {
const p = Object.keys(params).map(key => {
let val = params[key];
if ("[object Object]" === Object.prototype.toString.call(val) || Array.isArray(val)) {
keys.push(Array.isArray(params) ? "" : key);
return serializeQuery(val, keys, Array.isArray(val));
} else {
let tKey = keys.length > 0 ? ((isArray ? keys : [...keys, key]).reduce((str, k) => "" === str ? k : `${str}[${k}]`, "")) : key;
if (isArray) {
return encodeURIComponent(tKey) + '=' + encodeURIComponent(val);
}
}
}).join('&');
keys.pop();
return p;
}
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}
.as-console-row {
white-space: pre-wrap;
word-break: break-all;
}
In the checkboxes which pertains on the same class ,I'm using this function (not finished) tho loop and set a string
function estados() {
var query = "trucades.estat in(";
var checks = $('.estate_check:checked');
if (checks.length === 0) {
query = "not selected ";
} else {
//set the message here ...but only loops once
}
return query;
}
But checks only contains an object which contains the selected checkboxes but if I try to llop ,it only loops once ,because only contains this object
var ckbox = $('.my-checkbox:checked');
var str = "";
ckbox.each(function(){
str += $(this).attr('data-text') + ", ";
});
alert(str);
This fiddle helps you figure it out:
JSFiddle
Assuming you need to create query, You can use .map() along with .get() to create an array of selected values. then Array.join() can be used to create comma separated string.
function estados() {
var query = "trucades.estat in(";
var checks = $('.estate_check:checked');
if (checks.length === 0) {
query = "not selected ";
} else {
//Create an array of selected value
var selectedValue = checks.map(function () {
return $(this).val();
}).get();
query += selectedValue.join(',') + ')'
}
return query;
}
function estados() {
var query = "trucades.estat in(";
$('.estate_check:checked').each(function( index ) {
const val = $( this ).val()
console.log(index + ': ' + val);
query += val;
});
query += ')';
return query;
}
I am trying to get the "path" of an AngularJS scope variable and not having much luck. I want to eventually pass that "path" to be used as the ng-model of some dynamic forms that are being created.
Here is my code so far:
my_code.js:
var my_data = {
name: "fred",
number: 1,
children: [
{ name: "bob" },
{ name: "joe" },
{ name: "norman" },
]
};
function get_path(obj, target, path) {
if (typeof path === "undefined" || path === null) {
path = "my_data";
}
for (var key in obj) {
var value = obj[key];
var value_type = value.constructor;
/* value can either be an Array */
if (value_type === Array) {
for (var i=0; i<value.length; i++) {
if (value[i] === target) {
return path + "." + key + "[" + i + "]";
}
var result = get_path(value, target, path + "." + key + "[" + i + "]");
if (result) {
return result;
}
}
}
/* or an Object (dictionary) itself */
else if (value_type === Object) {
var result = get_path(value, target, path + "." + key);
if (result) {
return result;
}
}
/* or something atomic (string, number, etc.) */
else {
if (value === target) {
return path + "." + key;
}
}
}
return false;
}
If I pass the object my_data.children[0].name to this function, I would expect it to return the string "my_data.children[0].name". But it is actually returning "my_data.children[0].0.name". Any ideas on where I'm going wrong?
P.S. - I got the initial idea from Javascript/JSON get path to given subnode?, but that didn't handle Arrays.
I think your error is at :
else if (value_type === Object) {
var result = get_path(value, target, path + "." + key);
if (result) {
return result;
}
}
you have added "." + key. just remove it become like below:
else if (value_type === Object) {
var result = get_path(value, target, path );
if (result) {
return result;
}
}
#min-hong-tan solved the problem, and should be the accepted answer. But for completeness sake, I added the following lines:
if (value === target) {
return path + "." + key;
}
after each if block just in case I was trying to match an entire Array (as with my_data.children) or an entire Object that is not part of an Array.
I would like to iterate over the below and output a string that combines the different settings:
Loop through this:
config : {
settings : {
width: 880,
height: 495,
byline: false,
title: false,
portrait: false
}
}
And output:
var output = '&height=495&width=880&title=false&byline=false&portrait=false',
How would I go about this?
I don't know whether you explicitly want to loop, but you can simply use jQuery.param:
var output = "&" + $.param(obj.config.settings);
// I assumed `obj` contains `config`
The order may be different but for a query string that does not matter.
var attr, val, settings = config.settings,
output, count = 0;
if ('undefined' !== typeof settings) {
for (attr in settings) {
val = settings[attr];
if (0 === count) {
output = output + val;
} else {
output = output + '&' + val;
}
count += 1;
}
console.log(output);
}
Note, the above code adds the optimization where you don't add an & to the first var. I don't think you'd want that in a get var string. If you do, just change to output = output + val; starting from if to end of else.
How about this:
function print( obj ) {
return Object.keys( obj ).map( function ( name ) {
return '&' + name + '=' + obj[ name ];
}).join( '' );
}
Usage:
var output = print( obj.config.settings );
Live demo: http://jsfiddle.net/w3D9M/