Utility Mapper functions in javascript - javascript

I wanted to know if there is any way to write a mapper function in javascript, and by map functions I do not mean the ES6 map HOF,
What I really need is when I get an response or data and I wish to produce a conditional result out of it,
for example, if role:['ADMIN'] do this,
if role:['HEAD'] do this, now it can be done with if else or switch but I do not want to write conditionals for this, as in future there is a possibility more conditions will be handled. So is there a way to create a custom mapper function which does this, it can also be useful in api calls as when a user has a specific role he/she can make this specific API call
Please comment if you need more information.
Thank you

I don't know if that's the right way to do it but you could create an Object with functions in it.
This would look somewhat like that:
const map = {
'ADMIN': () => { console.log('your role is admin') },
'HEAD': () => { console.log('your role is head') }
};
map['ADMIN'](); // Outputs 'your role is admin'
But what if you, by any reason, received garbage data. Your code will error.
So you would either need to catch that error:
const role = 'blarg';
try {
map[role]();
} catch(e) {
console.log('submittet incorect data')
}
Or check if the role key exists in the object:
if(Object.keys(map).includes(role)) {
map[role]()
}
But to be honest I still think I would do something like:
function handleRole(role) {
switch(role) {
case 'ADMIN': function_for_admin(); break;
case 'HEAD': function_for_head(); break;
}
}
handleRole(role);

Related

More efficient way to handle an extremely specific response from a Rest API in JavaScript

I'm working with a Dungeons & Dragons 5e API and want that an especific result be treated in a special way. The user can choose what to search from a range of options, and in only one of them would I need to take care of the answer in a different way. In this option, I get the answer in JSON that contains a 'name' field, which stores a String, but in this specific case this String comes with an acronym, and I would like to transform it into the full name.I'm afraid to just put am 'if' statement in the middle of the code and deal with the situation inefficiently, even more so that I did not find similar situations to have any reference.
This is part of the result of the API I want to handle in a special way:
{"count":6,
"results":[
{"name":"STR",
"url":"http://www.dnd5eapi.co/api/ability-score/1"},
{"name":"DEX",
"url":"http://www.dnd5eapi.co/api/ability-scores2"},
....
]
}
This is how I handle the answer:
fetch(fullAPIURL)
.then(result => result.json())
.then(data => {
let resultContainer = document.getElementById('resultContainer');
//Cleaning the result container from previous results
document.querySelectorAll('#resultContainer article').forEach(container =>
resultContainer.removeChild(container));
spanSearchResult.classList.remove('invisible', 'searchFail');
spanSearchResult.classList.add('searchSucess');
spanSearchResult.innerHTML = `Search returned ${data.count} results`;
for (element of data.results) {
let containerTitle = element.name != undefined ? element.name : element.class;
resultContainer.appendChild(createResultContainer(containerTitle));
}
})
.catch(err => {
spanSearchResult.classList.remove('invisible');
spanSearchResult.classList.add('searchFail');
spanSearchResult.innerHTML = 'Something went wrong! Details in the console';
console.log(err);
});
Is putting a condition in this snippet of code really the most efficient way to solve this situation?
Thanks in advance.
You could just make a lookup call, actually. In fact, that'd be preferable if you ever want to port your application to another language, for example.
Define the following:
var retrieve = (function() {
var items = {
"STR": "Strength",
"DEX": "Dexterity"
};
return function(item) {
return items[item] || item;
}
})();
console.log(retrieve("DEX"));
With this, you can simply call retrieve(element.name) to retrieve its "actual" name. You can add elements to the object to create new translations, and if you ever need to support multiple languages, you can even replace the function entirely.

Where to implement the postback action code in a javascript chatbot

my question is regarding the implementation of this snippet of javascript code into my chatbot:
smooch.conversations.sendMessage('app_5790dca8cab9a256005c0148', {
text: 'Fabric',
role: 'appMaker',
actions: [
{
type: 'postback',
text: 'fabric instructions',
payload: 'egg_fabric'
}
]
}).then(() => {
// async code
});
Here is my script.json file that corresponds to this specific postback:
"HOW CAN I REMOVE AN EGG STAIN?": "%[Fabric](postback:egg_fabric) %[Surface](postback:egg_surface)",
The reason I am asking this question is because I want to have multiple "surface" and "fabric" buttons throughout the chat but I want the answer the bot spits out to correspond to the question most recently asked. Thanks for your help!
What you're looking for can't be done this with script.json, you'll have to define your own state functions in script.js, and your own postback event handling.
In this answer there are some suggestions as to how you can do this with the smooch-bot-example project (which is what estherbot was forked from).
To give you some context, script.js is where the actual bot logic lives. The script.json you're looking at is a shortcut that was introduced with estherbot to make it easier to define keyword-based bots. When your bot runs, the JSON actually gets compiled into states as if the were defined in script.js in the first place. What you're attempting to build will require more than the static keyword --> behaviour mapping that the script.json is limited to.
Following up on Andrew's answer above:
Check the smooch-bot-example project, but maybe start by looking into the webhook implementation file for the postbacks (heroku/index.js) instead of the bot logic/flow definition file (script.js) file:
Within the heroku folder of the repo, check the index.js file. The function handlePostback(req, res) (should be around line 109) should help you get started. E.g. change it to something like this:
From:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
createBot(req.body.appUser).say(`You said: ${postback.action.text} (payload was: ${postback.action.payload})`)
.then(() => res.end());
}
To something like:
function handlePostback(req, res) {
const postback = req.body.postbacks[0];
if (!postback || !postback.action) {
res.end();
}
const sAction = postback.action.text;
const sPayload = postback.action.payload;
switch (sAction) {
case "egg_fabric":
//something something
break;
case "egg_surface":
//something something
break;
default:
//something something
}
}
Hope that helps.

Passing values to a map function - CouchDB

I was wondering whether its possible to pass values to a map function in couchDB design document.
For Example:
In the code below is it possible to pass a value that has been entered by the user and use that value to run the map function. Maybe I can pass users UserName when they login and then display the view based on the map function.
function(doc) {
if(doc.name == data-Entered-By-User) {
emit(doc.type, doc);
}
}
Thank you in advance.
Regards
This is a common mistake in CouchDB when using views. It's kinda confusing, but instead of this:
function (doc) {
if (doc.value === 'thing I am looking for') {
emit(doc.value);
}
}
What you want is this:
function (doc) {
emit(doc.value);
}
And then when you query, you do:
/mydb/_design/myddoc/_view/myview?key="thing I am looking for"
You might want to read my 12 pro tips for better code with PouchDB, especially tip #9. The tips apply equally well to CouchDB. :)

Dynamically run a sequence of promises using Q

I am writing a SPA with typescript using breeze and knockout.
What I want to do is to create a launch manager, which can perform the neccessary steps required to even start the site (e.g. read configuration json, download odata metadata, initialize breeze metadata store and so on).
I've created the following to represent each step in the launch sequence:
export enum LauncherProgressStatus {
Ready,
InProgress,
Success,
Failed,
Aborted
}
export class LauncherProgressItem {
public status: KnockoutObservable<LauncherProgressStatus> = ko.observable<LauncherProgressStatus>();
public description: KnockoutObservable<String> = ko.observable<String>();
public statusText: KnockoutComputedFunctions<String> = ko.computed<String>(() => {
return LauncherProgressItem.getStatusText(this.status());
});
public start() {
this.action(this);
}
constructor(descriptionText: String,
public action: (arg: LauncherProgressItem) => Boolean) {
this.status(LauncherProgressStatus.InProgress);
this.description(descriptionText);
}
public static getStatusText(status: LauncherProgressStatus) : String {
switch (status) {
case LauncherProgressStatus.Ready:
return "Ready";
case LauncherProgressStatus.InProgress:
return "In progress";
case LauncherProgressStatus.Success:
return "Success";
case LauncherProgressStatus.Aborted:
return "Aborted";
default:
return "Failed";
}
}
}
TL;DR I create each step like this in code:
var item1 = new launcher.LauncherProgressItem("Loading configuration...", (item: LauncherProgressItem) => {
cfgMgr.setConfigurationFromFile("config.json?bust=" + (new Date()).getTime());
return true;
});
Now the problem: I want to utilize this to create a promise chain using Q. I can do this manually, i.e.
q.fcall(() => item1.action(item1))
.then(() => item2.action(item2))
.fail((r) => { console.log("Many whelps, HANDLE IT!") });
But I want to create some kind of manager object that doesnt really know how many steps is required. It will just be responsible for building an array of promises and execute them in sequence, whilst being able to detect errors (in the fail promise presumably) and abort the sequence.
The manager will have some kind of collection containing the LauncherProgressItem steps. Then I'm looking to build a chain of promises based on the content of that collection.
I've been looking at this for a while now but can't really seem to get my head around how to do this with Q. I've seen some examples etc but I don't really understand how it works.
Anyone got any suggestions on how to achieve this?
Update: I'll try to clarify what I am trying to achieve: My LauncherProgressItem wraps a lambda function and some state information which I bind to my view. This is why I am using these, but this is kind of irrelevant to what I'm actually struggling with.
So lets assume I have a class which contains an array of lambdas. This class has a method which will run all these lambas in sequence using Q, aborting on error. Exactly what I would achieve with the following code:
Q.fcall(doSomething).then(doSomethingElse).fail(reportError);
However, in this case doSomething and doSomethingElseresides in an array of functions, rather than a fixed number of steps. This is because I want it to be reusable, i.e. being able to run in multiple scenarios depending on the task at hand. So I want to avoid hard-coding the chain of functions to run.
Sorry I don't know typescript but I thought the comment thread above was not going very well, so here's the function you asked for in plain JS:
function runInSequence (functions) {
if (!functions || !functions.length) {
return;
}
var nextPromise = Q.fcall(functions[0]);
functions.slice(1).forEach(function (f) {
nextPromise = nextPromise.then(f);
});
nextPromise.fail(yourErrorHandler);
}

node.js/javascript/couchdb view to associative array does not seem to work

I am trying to create a webapp on a node/couchdb/windows stack but get terribly stung by what seems to be a lack of experience.
In the database, there is a view that returns all users with passwords. Based on the tutorial for a blog I have tried to access the view through my node code.
Whenever I investigate the structure of the users or users variable, I get an undefined object.
The call to getDatabase() has been tested elsewhere and works at least for creating new documents.
function GetUser(login)
{
var users = GetUsers();
return users[login];
}
function GetUsers() {
var db = getDatabase();
var usersByEmail = [];
db.view("accounts", "password_by_email")
.then(function (resp) {
resp.rows.forEach(function (x) { usersByEmail[x.key] = x.value});
});
//usersByEmail['test'] = 'test';
return usersByEmail;
}
I am aware that both the use of non-hashed passwords as well as reading all users from the database is prohibitive in the final product - just in case anyone wanted to comment on that.
In case something is wrong with the way I access the view: I am using a design document called '_design/accounts' with the view name 'password_by_email'.
Your call to db.view is asynchronous, so when you hit return usersByEmail the object hasn't yet been populated. You simply can't return values from async code; you need to have it make a callback that will execute the code that relies on the result.

Categories