Swapping out Constants for a Function - javascript

I'm trying to refactor the following code, which depending on the top level domain of the recipients email, changes where you click through to in my button. I currently do this with two consts, which I need to refactor into only one.
const CCENTERURL_AT= `${HOSTURL_AT}/ccenter/zendesk/landing/`;
const CCENTERURL = `${HOSTURL}.com/ccenter/zendesk/landing/`;
const recipientEmail = data.ticket.recipient;
var cCenterUrl;
if(recipientEmail.indexOf(".com") > 0)
{
cCenterUrl = getCcenterUrl(zendeskID)
}else{
cCenterUrl = getAustrianCcenterUrl(zendeskID)
}
function getCcenterUrl(ticketID) {
const cCenterTicketUrl = CCENTERURL + ticketID ;
return cCenterTicketUrl;
}
// Get Austrian Ccenter Ticket Url using Zendesk ticket ID
function getAustrianCcenterUrl(ticketID) {
const cCenterTicketUrlAustria = CCENTERURL_AT + ticketID ;
return cCenterTicketUrlAustria;
}
I know I should be able to create a function which will take recipient Email`s top-level domain as parameter and return appropriate URL for CCENTERURL. But no matter what I've tried its become overcomplicated or hasn't worked. I would be interested to hear peoples opinions on either how I can achieve my goal or even how it would be better to go about this!

So you basically want to combine these into one function and use a string template like this.
const HOSTURL = 'example.com/'
const HOSTURL_AT = 'example.au/'
const reAu = /\.au$/;
const getTicketURL = (
(mail, id) => `${ reAu.test(mail) > 0 ? HOSTURL : HOSTURL_AT }ccenter/zendesk/landing/${id}`
);
// Test AU
console.log(getTicketURL('foo#google.com.au', 'ABC1231'))
// Test US
console.log(getTicketURL('foo#google.com', 'ABC1231'))

Related

Async JS validation issues for html textarea

I'm trying to replicate the code in this article:
https://depth-first.com/articles/2020/08/24/smiles-validation-in-the-browser/
What I'm trying to do different is that I'm using a textarea instead of input to take multi-line input. In addition to displaying an error message, I also want to display the entry which doesn't pass the validation.
The original validation script is this:
const path = '/target/wasm32-unknown-unknown/release/smival.wasm';
const read_smiles = instance => {
return smiles => {
const encoder = new TextEncoder();
const encoded = encoder.encode(`${smiles}\0`);
const length = encoded.length;
const pString = instance.exports.alloc(length);
const view = new Uint8Array(
instance.exports.memory.buffer, pString, length
);
view.set(encoded);
return instance.exports.read_smiles(pString);
};
};
const watch = instance => {
const read = read_smiles(instance);
document.querySelector('input').addEventListener('input', e => {
const { target } = e;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
(async () => {
const response = await fetch(path);
const bytes = await response.arrayBuffer();
const wasm = await WebAssembly.instantiate(bytes, { });
watch(wasm.instance);
})();
For working with a textarea, I've changed the watch function to this and added a <p id="indicator"> element to the html to display an error:
const watch = instance => {
const read = read_smiles(instance);
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
var lines_array = target.value.split('/n');
var p = document.getElementById("indicator");
p.style.display = "block";
p.innerHTML = "The size of the input is : " + lines_array.length;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
I'm not even able to get a count of entries that fail the validation. I believe this is async js and I'm just a beginner in JavaScript so it's hard to follow what is happening here, especially the part where the function e is referencing itself.
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
Can someone please help me in understanding this complicated code and figuring out how to get a count of entries that fail the validation and also printing the string/index of the same for helping the user?
There is a mistake in you code to count entries in the textarea:
var lines_array = target.value.split('\n'); // replace /n with \n
You are asking about the function e is referencing itself:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can find more informations Mdn web docs - Destructuring object

Javascript While Loop Error with User Input

I am just beginning with JS and am having trouble with scope and executing code in similar style as I would with Python. I have started learning JS on Codecademy and have just begun my first project.
My code for the project is below:
//////////////////////////
// R U Hungry Console App
/////////////////////////
// Step 1: Load in Necessary Modules
////////////////////////////////////
// add in the prompt-sync module
// allows to take in and display users name
const prompt = require('prompt-sync')();
// load in fs module
// allows reading in from text files
const fs = require("fs");
// load open module
//allows the opening of webpages
const open = require('open');
// Step 2: Create a menu object
///////////////////////////////
const menu = {
starters: [],
mains: [],
desserts: []
}
// Step 3 Create a factory function to update the Menu object
/////////////////////////////////////////////////////////////
const menuUpdate = (course,dishName,dishLink) => {
if (course.toLowerCase() === 'starter'){
let newItem = {dish: dishName, link: dishLink};
menu.starters.push(newItem);
} else if (course.toLowerCase() === 'main'){
let newItem = {dish: dishName, link: dishLink};
menu.mains.push(newItem);
} else if (course.toLowerCase() === 'dessert'){
let newItem = {dish: dishName, link: dishLink};
menu.desserts.push(newItem);
} else {
console.log('You did not enter a valid course.\nCould not update menu');
}
}
// Step 4: Read in text files of scraped web data
/////////////////////////////////////////////////
const dishes = [menu.starters,menu.mains,menu.desserts];
const filesToRead = ['starters.txt','mains.txt','desserts.txt'];
function addFiles(course,file){
const text = fs.readFileSync(`./menu_files/${file}`);
const textByLine = text.toString().split("\n");
for (const line of textByLine){
course.push(line);
}
}
addFiles(dishes[0],filesToRead[0]);
addFiles(dishes[1],filesToRead[1]);
addFiles(dishes[2],filesToRead[2]);
// Step 5: Put it all together
//////////////////////////////
console.log('\n\nFeeling hungry and can\'t decide what to eat? You have come to the right place.')
const name = prompt('What is your name? ');
console.log(`\nWelcome, ${name}!\nWould you like to be:\n1.Presented With a Menu\n2.Add a Dish to the Menu`);
let userChoice;
while (true){
userChoice = prompt('\nEnter 1 to get a Menu\nEnter 2 to add a Menu Item\nEnter 3 to exit R U Hungry ');
if (userChoice.trim() === 1){
const starterSelector = Math.floor(Math.random() * menu.starters.length);
const mainSelector = Math.floor(Math.random() * menu.mains.length);
const dessertSelector = Math.floor(Math.random() * menu.desserts.length);
let starterDish = menu.starters[starterSelector][0];
let starterRecipe = menu.starters[starterSelector][1];
let mainDish = menu.mains[mainsSelector][0];
let mainRecipe = menu.mains[mainsSelector][1];
let dessertDish = menu.desserts[dessertSelector][0];
let dessertRecipe = menu.desserts[dessertSelector][1];
console.log(`${name}, your Menu is as follows:\n`);
console.log(`Starter: ${starterDish}`);
console.log(`Main: ${mainDish}`);
console.log(`Dessert: ${dessertDish}`);
console.log('\nWe will direct you to recipes for your selected dishes');
// opens the url in the default browser
open(starterRecipe);
open(mainRecipe);
open(dessertRecipe);
} else if (userChoice.trim() === 2){
let userCourse = prompt('Is your dish a Starter, Main or Dessert? ');
let userDishName = prompt('Great! Please tell me the name of your dish ');
let userDishLink = prompt('Please provide the link to the dish recipe ');
menuUpdate = (userCourse,userDishName,userDishLink);
console.log('Menu updated with your dish!');
} else {
console.log(`Goodbye, ${name}.`);
break;
}
console.log('Would you like to perform another function?');
}
// End
I am having trouble with the while loop at the end.
This part specifically:
let userChoice;
while (true){
userChoice = prompt('\nEnter 1 to get a Menu\nEnter 2 to add a Menu Item\nEnter 3 to exit R U Hungry ');
if (userChoice.trim() === 1){
const starterSelector = Math.floor(Math.random() * menu.starters.length);
const mainSelector = Math.floor(Math.random() * menu.mains.length);
const dessertSelector = Math.floor(Math.random() * menu.desserts.length);
let starterDish = menu.starters[starterSelector][0];
let starterRecipe = menu.starters[starterSelector][1];
let mainDish = menu.mains[mainsSelector][0];
let mainRecipe = menu.mains[mainsSelector][1];
let dessertDish = menu.desserts[dessertSelector][0];
let dessertRecipe = menu.desserts[dessertSelector][1];
console.log(`${name}, your Menu is as follows:\n`);
console.log(`Starter: ${starterDish}`);
console.log(`Main: ${mainDish}`);
console.log(`Dessert: ${dessertDish}`);
console.log('\nWe will direct you to recipes for your selected dishes');
// opens the url in the default browser
open(starterRecipe);
open(mainRecipe);
open(dessertRecipe);
} else if (userChoice.trim() === 2){
let userCourse = prompt('Is your dish a Starter, Main or Dessert? ');
let userDishName = prompt('Great! Please tell me the name of your dish ');
let userDishLink = prompt('Please provide the link to the dish recipe ');
menuUpdate = (userCourse,userDishName,userDishLink);
console.log('Menu updated with your dish!');
} else {
console.log(`Goodbye, ${name}.`);
break;
}
console.log('Would you like to perform another function?');
}
It keeps executing the code in the else block and then exiting the program.
In python I would have used something like this:
while (True):
choice = input("What is your name? ")
if choice.strip().lower() != 'john':
print("Who are you?")
break;
elif choice choice.strip().lower() != 'shaun':
print("Who are you?")
break;
else:
print("Hi there, glad you aren't John or Shaun")
continue
Stupid example but I just wanted to show how I could normally have achieved something like this before.
Would anyone be able to explain what is incorrect?
I also struggle to understand the scope in JS. Is that perhaps the problem here?
I am finding it difficult in some cases to apply my thinking from Python to JS.
Any help would be appreciated. I am really wanting to learn.
Thanks!
Maybe as a starter you can you == rather than === as it would not match the type, also in your else if it seems you are calling function incorrectly, remove =.

Value is not changing in real time -- VueJS

I am using a JS class, I have following code:
class Field {
public Value = null;
public Items = [];
public UniqueKey = null;
public getItems() {
let items = [...this.Items];
items = items.filter((item) => {
if (item.VisibleIf) {
const matched = item.VisibleIf.match(/\$\[input:(.*?)\]/g);
if (matched?.length) {
const srv = Service.getInstance();
for (let match of matched) {
match = match.slice(8, -1);
if (srv.Fields?.length) {
let found = srv.Fields.find((x) => x.UniqueKey === match);
if (found) {
item.VisibleIf = item.VisibleIf.replace(
`$[input:${match}]`,
found.Value ?? ''
);
return JSON.parse('' + eval(item.VisibleIf));
}
}
}
}
}
return true;
});
return items;
}
public getInputTitle() {
let title = this.Title;
const matched = title.match(/\$\[input:(.*?)\]/g);
if (matched?.length && title) {
const srv = Service.getInstance();
for (let match of matched) {
match = match.slice(8, -1);
if (srv.Fields?.length) {
let found = srv.Fields.find((x) => x.UniqueKey === match);
if (found) {
title = title.replace(`$[input:${match}]`, found.Value ?? '');
}
}
}
}
return title;
}
}
Now I have a Vue component:
<div v-for="Field in Fields" :key="Field.UniqueKey">
<v-select
v-if="Field.Type == 'Select'"
:label="Field.getInputTitle()"
v-model="Field.Value"
:items="Field.getItems()"
item-text="Value"
item-value="Id"
/>
<v-input
v-else-if="Field.Type == 'Input'"
v-model="Field.Value"
:label="Field.getInputTitle()"
/>
</div>
// JS
const srv = Service.getInstance();
Fields = srv.getFields(); // <- API call will be there.
So basically, data comes from an API, having Title as Input $[input:uniqueKey], in a component I am looping over the data and generating the fields. See getInputTitle function in Field class, it works very well. All the fields which are dependent on the $[input:uniqueKey] are changing when I start typing into that field on which other fields are dependent.
Now I have pretty much same concept in the getItems function, so basically, what I want to do is whenever I type into a field and that field exists in the VisibleIf on the Items, the VisibleIf will be like '$[input:uniqueKey] < 1', or any other valid JavaScript expression which can be solved by eval function. But the getItems function is called only 1st time when page gets loaded, on the other hand the getInputTitle function which is pretty much same, gets called every time when I type into the field.
I tried to explain at my best, I will provide any necessary information if needed.
Any solution will be appreciated. Thanks.
You are updating the Object itself in here:
item.VisibleIf = item.VisibleIf.replace( `$[input:${match}]`, found.Value ?? '' );
Even though you tried to copy the array, but you have done shallow copy of the object in here: let items = [...this.Config.Items];
I suggest the following solution:
const visibleIf = item.VisibleIf.replace(
`$[input:${match}]`,
found.Value ?? ''
);
const val = '' + helpers.evalExp('' + visibleIf);
if (helpers.isJSON(val)) {
return JSON.parse(val);
}
Means instead of changing the VisibleIf object, just store it into the variable and just use that.
I hope that it will fix your issue. Let me know if it works.

Get one element from JS array, in any click

I have a constuctor function and a button. I want to get a name of one client in each click. but when I click one time, I get the name of all the clients in a sequence.
function Client(Name, Feedback) {
this.clientName = Name;
this.clientFeedback = Feedback;
}
let clients = [
new Client('Jo', 'hi'),
new Client('Mark', 'bye'),
]
let btnRight = document.getElementById('btnRight');
btnRight.addEventListener('click', () => {
for (let Client of clients) {
console.log(`${Client.clientName} says ${Client.clientFeedback}!`)
}
})
<button class="btn" id="btnRight">button</button>
I'm absolute beginner, so any feedback will help me
Don't loop in your event handler. Instead, keep track of where you are in the array outside the handler, for instance (see *** comments):
function Client(Name, Feedback){
this.clientName = Name;
this.clientFeedback = Feedback;
}
let clients = [
new Client('Jo', 'Hi' ),
new Client('Mark', 'Bye'),
];
let index = 0; // The next client to show
let btnRight = document.getElementById('btnRight');
btnRight.addEventListener('click', () => {
// *** Get this client
const client = clients[index];
// *** Set up the next click (looping around back to the start if necessary)
index = (index + 1) % clients.length;
// *** Show result
alert(`${client.clientName} says ${client.clientFeedback}!`)
});
<button class="btn" id="btnRight">button</button>
If you don't want to loop back to the beginning, keep a reference to the event handler and remove it when you run out of clients (or similar).
Some side notes:
I suggest learning the rules for where semicolons go and then consistently including them (my preference) or leaving them out (relying on automatic semicolon insertion), but not mixing the two. :-) My guess is that you just left some out accidentally — and fair enough, you're new!
I strongly, strongly recommend not putting the closing } at the end of the last statement in a block. It's hard to read (subjective) and hard to maintain (objective; you have to muck about if you need to add another statement). Use any of the standard styles, all of which put the closing } on its own line after the block.
I suggest not using initially-capped variables (client in your for (const Client of clients)) for things other than constructor functions (and type names, in TypeScript), at least not in code you'll be working on with other people or asking for help with, etc. The overwhelming convention is to start a variable with a lower case letter when it's not referring to a constructor function.
Finally, consistent indentation is useful for when you're reading code. I'm a strongly believer in four-space (or one tab) indentation, but two spaces is (sadly) very common. Whatever you choose, consistency is the key thing.
Suggest removing the foreach inside the click function. And add a variable to track the count of clicks.
function Client(Name, Feedback){
this.clientName = Name;
this.clientFeedback = Feedback;
}
let clients = [
new Client('Jo', 'Hi' ),
new Client('Mark', 'Bye'),
]
let btnRight = document.getElementById('btnRight');
let clickIndex = 0;
btnRight.addEventListener('click', () => {
alert(`${clients[clickIndex].clientName} says ${clients[clickIndex].clientFeedback}!`)
clickIndex += 1;
if(clickIndex > clients.length - 1)
clickIndex = 0;
})
function Client(Name, Feedback) {
this.clientName = Name;
this.clientFeedback = Feedback;
}
let clients = [
new Client('Jo', 'Hi'),
new Client('Mark', 'Bye'),
]
let currentIndex=0
let btnRight = document.getElementById('btnRight');
btnRight.addEventListener('click', () => {
alert(`${clients[currentIndex].clientName} says ${clients[currentIndex].clientFeedback}!`)
currentIndex++
if(currentIndex >= clients.length){
currentIndex=0;
}
})
<button class="btn" id="btnRight">button</button>
All of the above answers are correct, yet here is another solution using javascript yield:
function Client(Name, Feedback) {
this.clientName = Name;
this.clientFeedback = Feedback;
}
let clients = [
new Client('Jo', 'Hi'),
new Client('Mark', 'Bye'),
]
let btnRight = document.getElementById('btnRight');
function* yieldClient(index = 0) {
while(true) {
yield(clients[index]);
index = (index + 1) % 2;
}
}
const clientIterator = yieldClient();
btnRight.addEventListener('click', () => {
const Client = clientIterator.next().value;
console.log(`${Client.clientName} says ${Client.clientFeedback}!`)
})
<button class="btn" id="btnRight">button</button>

How does one parent a channel to a category with a discord bot?

Basically there is no errors in the output but at the same time it's not doing what I'm trying to achieve.
Ive been tinkering with the script for 5 hours straight mixing up line positioning and now I got it to where it gives me the promise (my initial issue) but I cant parent the channel.
I've tried discord.js server and site, youtube, 2 other sites i forgot the name of but i cant crack it.
function setup(arguments, message){
var server = message.guild;
var name = message.author.username;
let searchquery = arguments.join("")
let cat = server.createChannel("Important", "category");
async function Channelmaker(Sent, obj){
try {
let chan = await server.createChannel(Sent, "Text");
//console.log(obj);
return chan
} catch(prom){
var chan2 = await server.createChannel(Sent, "Text");
return new Promise(resolve => {
var chan2 = server.createChannel(Sent, "Text", parent = obj);
resolve(chan2)
});
}
}
var holding
var chan = Channelmaker("⚖️ rules ⚖️", cat).then(value => {
console.log(value)
holding = value
value.parentID = cat
chan.setParent(cat.Id)
}).catch(error => {
// s
});
console.log("holding")
console.log(holding)
}
The category is not the parent of the "⚖️ rules ⚖️" channel that is created which is the opposite of what I'm trying to achieve
In Guild.createChannel(), use the options parameter including ChannelData, like so:
await server.createChannel(Sent, {
// You can omit the 'type' property; it's 'text' by default.
parent: obj
});

Categories

Resources