Conditional statement within template literal concatenation? - javascript

I am making an API call like this:
posts: (ppp, page) =>
requests.get(`/wp-json/wp/v2/posts?per_page=${ppp}&page=${page}`)
I am not always going to be passing in posts per page or page though, so I would like to only concatenate those variables if they exist. I tried below but I can't seem to get the formatting down:
requests.get(`/wp-json/wp/v2/posts?`${ppp ? `'per_page='${ppp} : `''` `${page} ? `'&page=' ${page}` :''`)

Besides that your second solution contains syntax errors, it also isn't the most readable way to do that...
But why are you trying to reinvent the wheel?
You can use the URL API which is available both on the client-side and in Node.js:
posts: (ppp, page) => {
const url = new URL('/wp-json/wp/v2/posts')
if(ppp) url.searchParams.append('per_page', ppp)
if(page) url.searchParams.append('page', page)
return requests.get(url.href)
}
However, if you can't use the above solution for some reason, you can still implement a similar algorithm that works like the above solution. For example, you can use an array:
posts: (ppp, page) => {
const urlParams = []
if(ppp) urlParams.push(`per_page=${ppp}`)
if(page) urlParams.push(`page=${page}`)
return requests.get(`/wp-json/wp/v2/posts?${ urlParams.join('&') }`)
}
Or an even more flexible solution:
posts: (ppp, page) => {
const urlParams = {
per_page: ppp, //per_page=ppp
page, //page=page
//Add more here if you want
}
return requests.get(`/wp-json/wp/v2/posts?${
Object
.entries(urlParams)
.filter(([k, v]) => v) //If value is truthy
.map(e => e.join('=')) //Concatenate key and value with =
.join('&') //Concatenate key-value pairs with &
}`)
}
But, if you want to stick to you version, here's a fixed example of it:
requests.get(`/wp-json/wp/v2/posts?${ppp ? `per_page=${ppp}` : ''}${(ppp && page) ? '&' : ''}${page ? `page=${page}` : ''}`)

Related

Check if two URL strings are equal

I'm building out a function to handle dynamic phone number swapping, identifying the referral url, mapping through a data set, and then outputting the promoUrl's related phone number. The data is formatted like this:
const phoneNumbers = [
{
promoUrl: '/interior-doors/',
promoNumber: '589-918-0710',
},
{
promoUrl: '/promo4/',
promoNumber: '307-789-8615',
},
];
And the function maps through the data and reduces it, allowing me to sort through it like this:
const url = location.pathname.replace(/\/+$/, '');
const promoNumber = phoneNumbers.reduce((promoNumber, results) => {
const hasPromo = results.promoUrl.includes(url);
if (hasPromo) {
return results.promoNumber;
}
return promoNumber;
}, '');
I'm having some issues with hasPromo. The way it's built right now allows for the promoUrl to have some variance and still work, meaning as long as it includes what is returned from url then it works i.e. /interior-doors/, /interior-doors, and interior-doors will all work, which is great, but it also works if url is /interior-do. I need it to not do that. It should work independent of formatting, but only return the promoNumber if the string of letters is exact.
I'm assuming this is a regex thing, but I don't know what I'm doing with regex. Any help would be greatly appreciated.
Use == to do an exact match. And since the promoURL property always has / around it, add those delimiters when you set url
const url = '/' + location.pathname.replace(/\/+$/, '') + '/';
const promoNumber = phoneNumbers.reduce((promoNumber, results) => {
const hasPromo = results.promoUrl == url;
if (hasPromo) {
return results.promoNumber;
}
return promoNumber;
}, '');
reduce also seems like the wrong function for this. You just need to find the matching promoUrl, you don't have to continue reducing, since the reduction function doesn't merge the results in any way.
const promo = phoneNumbers.find(({promoUrl}) => promoUrl == url);
const promoNumber = promo ? promo.promoNumber : '';

ReactJS: Join map output with concatenating value

In my ReactJS application I am getting the mobile numbers as a string which I need to break and generate a link for them to be clickable on the mobile devices. But, instead I am getting [object Object], [object Object] as an output, whereas it should be xxxxx, xxxxx, ....
Also, I need to move this mobileNumbers function to a separate location where it can be accessed via multiple components.
For example: Currently this code is located in the Footer component and this code is also need on the Contact Us component.
...
function isEmpty(value) {
return ((value === undefined) || (value === null))
? ''
: value;
};
function mobileNumbers(value) {
const returning = [];
if(isEmpty(value))
{
var data = value.split(',');
data.map((number, index) => {
var trimed = number.trim();
returning.push(<NavLink to={`tel:${trimed}`} key={index}>{trimed}</NavLink>);
});
return returning.join(', ');
}
return '';
};
...
What am I doing wrong here?
Is there any way to create a separate file for the common constants / functions like this to be accessed when needed?
First question:
What am I doing wrong here?
The issue what you have is happening because of Array.prototype.join(). If creates a string at the end of the day. From the documentation:
The join() method creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator.
Think about the following:
const navLinks = [{link:'randomlink'}, {link:'randomlink2'}];
console.log(navLinks.join(','))
If you would like to use concatenate with , then you can do similarly like this:
function mobileNumbers(value) {
if(isEmpty(value)) {
const data = value.split(',');
return data.map((number, index) => {
const trimed = number.trim();
return <NavLink to={`tel:${trimed}`} key={index}>{trimed}</NavLink>;
}).reduce((prev, curr) => [prev, ', ', curr]);
}
return [];
};
Then you need to use map() in JSX to make it work.
Second question:
Is there any way to create a separate file for the common constants / functions like this to be accessed when needed?
Usually what I do for constants is that I create in the src folder a file called Consts.js and put there as the following:
export default {
AppLogo: 'assets/logo_large.jpg',
AppTitle: 'Some app name',
RunFunction: function() { console.log(`I'm running`) }
}
Then simply import in a component when something is needed like:
import Consts from './Consts';
And using in render for example:
return <>
<h1>{Consts.AppTitle}</h1>
</>
Similarly you can call functions as well.
+1 suggestion:
Array.prototype.map() returns an array so you don't need to create one as you did earlier. From the documentation:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
I hope this helps!

ReactJS / ES6: Searching Japanese text using includes?

So, I'm writing a client-side search and I need to look through strings of Japanese characters. I'm wondering how to do this properly?... i.e. Do I change the format of the text into utf-8 something and then search the utf-8?
Example:
All my data has japaneseData.title : "フェリーチェ三田"
When I type in my search.value as : "フェ" using japaneseData.title.includes(search.value) I don't get a match...
How do I do this correctly?
Okay, after further inspection, the comments were correct and includes was finding the substring. This is all happening inside of a filter() and I'm trying to return the objects that match...
After changing my code to:
let filteredArrayofObjects = Lists.houseLists.filter(house => house.building_name.includes(query.search));
I was getting back some but not all. Problem cases:
"アーバイルスパシエ芝浦BAY-SIDE".includes("エ芝浦"); // this evaluates to true, but does not get included in my filtered array...
Okay, further digging, it seems the issue is I need to wait for the filter process before returning the results... haven't yet found a solution to that just yet.
async filter(arr, callback) {
return (await Promise.all(
arr.map(async item => {
return (await callback(item)) ? item : undefined;
})
)).filter(i => i !== undefined);
}
handleFilterLists = async (query = {}) => {
const { Lists } = this.props;
let searchResults = await this.filter(Lists.houseLists, async house => {
return house.building_name.includes(query.search);
// the final evaluation to look similar to this:
// var newArray = homes.filter(function (el) {
// return el.price <= 1000 &&
// el.sqft >= 500 &&
// el.num_of_beds >=2 &&
// el.num_of_baths >= 2.5;
// });
});
this.setState({ searchResults });
}
Okay, so, I'm trying to set state.searchResults after the filter method has checked for matching objects in the array Lists.houseLists...
includes returns true or false if the substring is detected or not. If you want the index of where the first detected substring begins, use indexOf.
I used your sample source and search text with includes and it returns true.
Edit:
I used your updated data and this still works. https://codepen.io/anon/pen/RMWpwe
const sourceText = 'アーバイルスパシエ芝浦BAY-SIDE';
const searchText = 'エ芝浦';
const lists = [
'スパシエ',
'芝浦BAY-SIDE',
'エ芝浦',
'パシエ芝浦BAY'
];
console.log(lists.filter(item => item.includes(searchText)));
// ["エ芝浦", "パシエ芝浦BAY"]

Dynogels: Query using OR comparison

I am trying to optimise the following scans into a single scan (or query). The only way I see is to use to use a OR comparator using DynamoDB. I am using dynogels (fork of vogels) in my application but sadly I am not aware of any OR query functionality in there.
let arrivals = yield Reservation.scan()
.where('room').equals(room)
.where('arrival').between(from, to)
.execAsync().then((reply) => reply.Items.map((item) => item.get()));
let departures = yield Reservation.scan()
.where('room').equals(room)
.where('departure').between(from, to)
.execAsync().then((reply) => reply.Items.map((item) => item.get()));
let combined = arrivals.concat(departures);
return Promise.resolve(combined);
Proposed optimisation:
return Reservation.scan()
.where('room').equals(room)
.where('arrival').between(from, to)
.or.where('departure').between(from, to)
.execAsync().then((reply) => reply.Items.map((item) => item.get()));
The scans get me the reservations that end (departure) or start (arrival) (or both) in a specified date range (from, to).
I think this can be achieved using filterexpression.
Sample code using filterexpression:-
const scanItem = Reservation.scan().filterExpression('room = :idVal AND ((arrival BETWEEN :arrDateVal1 AND :arrDateVal2) OR (departure BETWEEN :depDateVal1 AND :depDateVal2)) ')
.expressionAttributeValues({ ':idVal' : '2', ':arrDateVal1' : '21-APR-2017', ':arrDateVal2' : '23-APR-2017'
,':depDateVal1' : '21-APR-2017', ':depDateVal2' : '23-APR-2017'});
scanItem.exec((err, result) => {if(!err) {console.log(JSON.stringify(result,undefined, 2))}});
Note:-
Not sure whether you wanted to specifically use where rather than filterexpression (or) just wanted to achieve the result regardless of where or filterexpression.

How to map hash pattern to string value?

I want to map what is in the location hash to a string. The mapping has to be based on a pattern below (:Placeholder would be arbitrary numbers, maybe RegEx?). What is the best way to handle this in a function?
'news/:NewsID/dup' => 'newsDuplicate',
'news/:NewsID' => 'newsDetail',
'news/:NewsID/authors' => 'authorsList',
'news/:NewsID/authors/' => 'authorsList',
'news/:NewsID/authors/create' => 'authorsCreate',
'news/:NewsID/authors/:AuthorID' => 'authorDetail',
'news/:NewsID/authors/:AuthorID/orders' => 'orders',
'news/:NewsID/authors/:AuthorID/workflow' => 'workflow',
'news/:NewsID/authors/:AuthorID/tags' => 'tags'
I am trying to highlight the correct button in a navigation and wanted a function like handleNav() which would highlight the right button based on the pattern.
For example, when at http://mydomain.com#!news/123/authors/987, then I can do something like this:
function handleNav() {
var current = ?? //get mapped string above
$('button.' + current).addClass('active').siblings().removeClass('active');
}
How do I get the "current" variable above based on the mapping? Not sure if a bunch of if-else statements would be the best way and I do not know much regex. Thanks for any help or insight.
Perhaps normalize the string before reading the mapping? Something like this:
var map = {
'news/ID/dup' : 'newsDuplicate',
'news/ID' : 'newsDetail',
'news/ID/authors' : 'authorsList',
'news/ID/authors/' : 'authorsList',
'news/ID/authors/create' : 'authorsCreate',
'news/ID/authors/:AuthorID' : 'authorDetail',
'news/ID/authors/:AuthorID/orders' : 'orders',
'news/ID/authors/:AuthorID/workflow' : 'workflow',
'news/ID/authors/:AuthorID/tags' : 'tags'
}
function normalize(str) {
return str.replace(/news\/\d+/,'news/ID')
}
var current = map[normalize(url)];

Categories