I'm making a simple note app. Each note has a title, a body and a complete status. I want to create it so that if a note is not completed, it creates a button under the note. Upon clicking the button it should change the boolean value of complete to true and repopulate the list.
The problem I'm experiencing is that if the title has a space in it, I get an error:
This only happens when there is a space in the title(clicked on Family time). Does anyone know what the issue is? I've tried to create note.title as a variable then add it in. I've also tried to note.title.toString() with no luck. Here is the function:
function populateList(theList)
{
let divList = document.querySelector('#ListDiv');
divList.innerHTML = "";
theList.forEach(function(note)
{
let element = document.createElement('p');
let titleName = note.title.toLowerCase();
element.innerHTML = `Title: ${note.title}<br>Body: ${note.body}<br>Completed:${note.completed}`;
if(note.completed == false)
{
element.innerHTML += `<br><button onclick=completeNote("${note.title}")>Complete</button>`;
}
divList.appendChild(element);
});
}
Here you can use encodeURIComponent & decodeURIComponent like below:
function populateList(theList)
{
let divList = document.querySelector('#ListDiv');
divList.innerHTML = "";
theList.forEach(function(note)
{
let element = document.createElement('p');
let titleName = note.title.toLowerCase();
element.innerHTML = `Title: ${note.title}<br>Body: ${note.body}<br>Completed:${note.completed}`;
if(note.completed == false)
{
element.innerHTML += "<br><button onclick=completeNote('" + encodeURIComponent(note.title) + "')>Complete</button>";
}
divList.appendChild(element);
});
}
function completeNote(title){
theList.forEach(x=>{if(x.title == decodeURIComponent(title)){x.completed =true}});
populateList(theList);
}
You should add a note ID to your objects and when you click the button, pass the ID to the function to find the node and set it's status to completed.
After you change the status, re-render the list.
const notes = [
{ id: 1, title: 'Morning', body: 'Get out of bed', completed: true },
{ id: 2, title: 'Day', body: 'Work', completed: false },
{ id: 3, title: 'Evening', body: 'Go to bed', completed: false }
];
populateList(notes);
function completeNote(noteId) {
notes.find(note => note.id === parseInt(noteId, 10)).completed = true;
populateList(notes);
}
function populateList(theList) {
const divList = document.querySelector('#ListDiv');
divList.innerHTML = "";
theList.forEach(note => {
let element = document.createElement('p');
let titleName = note.title.toLowerCase();
element.innerHTML = `Title: ${note.title}<br>Body: ${note.body}<br>Completed: ${note.completed}`;
if (note.completed == false) {
element.innerHTML += `<br><button onclick=completeNote("${note.id}")>Complete</button>`;
}
divList.appendChild(element);
});
}
<div id="ListDiv"></div>
Related
I want to make a bot, this is my first one, just to mess with a buddy of mine. Essentially I want it to reply with a random message ANY time he writes in chat.
I have seen a lot used for banning and have found some that could work but I cannot seem to figure out how to have it work for anytime they press enter no matter the words in it.
This seems to be the closest I have found:
const userID = '4608164XXX93150209';
bot.on('message', function(message) {
if (!message.sender === userID) {
if (message.content === 'psst') {
message.channel.send('Hello there!');
}
}
});
Any help will be appreciated.
Just to be clear I want them to say anything in chat at all, no prefix needed, and have the bot reply with something random from a predefined list but ONLY for that one user.
Assuming you're using discord.js, which it looks like you are, you'll need to use the message.author property.
const specificUsers = ['ID Here', 'ID #2', 'ID #3', 'etc.']; // list of ids to detect
const messages = ['Message 1', 'Message 2', 'Message 3']; // list of messages to pick random from
// message event
bot.on('message', (message) => {
// if the author's id matches one of the blacklisted ids
if (specificUsers.includes(message.author.id))
// send random message from array
return message.channel.send(
messages[Math.floor(Math.random() * messages.length)]
);
});
const specificUsers = ['123456789', '987654321']; // list of ids to detect
const messages = ['hello', 'goodbye']; // list of messages to pick random from
// example message event
const message = {
content: 'hello',
author: {
id: '123456789'
}
}
// if the author's id matches one of the blacklisted ids
if (specificUsers.includes(message.author.id))
// send random message from array
console.log(messages[Math.floor(Math.random() * messages.length)]);
whatever I understood from you question, below code is more readable:
const blocked_users = ['4608164XXX93150209']; //you may have one more friend like him
bot.on('message', function(message) {
if (blocked_users.indexOf(message.sender) === -1) {
if (message.content === 'psst') {
message.channel.send('Hello there!');
}
} else {
message.channel.send('Get Away from this channel!');
}
});
Here is some code I used to generate random messages from an input string. It relies on a text file textcorpus.txt in the same directory to work. YOu can fill up this file with short stories from the internet.
Use the run function as an example to generate a random conversation. Since this is typescript and you probably want javascript just remove all the parts, your javascript linter is not happy about and it should work.
run();
async function run() {
console.log(`START CONVERSATION, LENGTH: ${100} CHUNKS`);
let conversationLength = 100;
function togglePartner(partner: string) {
if (partner == 'Anton') return 'Bella';
if (partner == 'Bella') return 'Anton';
else return 'Anton';
}
const sendMessage = console.log;
let i = 0;
let lastMessage = '';
let partner = 'Anton';
while (i < conversationLength) {
let res = await getResponse(lastMessage);
res.forEach((sen) => {
sendMessage(`${partner}: ${sen}`);
lastMessage = sen;
});
partner = togglePartner(partner);
i++;
}
}
function roll(zto: number) {
return Math.random() < zto;
}
export function randomBetween(x: number, y: number) {
return x + Math.floor(Math.random() * (y - x));
}
export function randomChoice(choices: Array<any>) {
var index = Math.floor(Math.random() * choices.length);
return choices[index];
}
export async function getResponse(input: string): Promise<Array<string>> {
// only affirmation + dryup:
let finalArray = [];
if (input[input.length - 1] == '?') finalArray.push(affirmation());
else if (roll(0.4)) {
// frage zurück stellen.
finalArray.push(question(input));
} else {
let file = await promises.readFile('./textcorpus.txt');
let corpus = file.toString();
let areaIndexStart = randomBetween(0, corpus.length - 300);
let area = corpus.substring(areaIndexStart, areaIndexStart + 300);
area = area.replace(/[\s]/g, ' ');
area = area.replace(/["']/g, '');
let sentences = area.split(/[.!?]/).map((s) => s.trim());
sentences.pop();
sentences.shift();
if (sentences.length < 1) {
finalArray.push(affirmation());
} else {
// determine count of sentences to return:
let senNum = randomBetween(1, Math.min(sentences.length, 5));
for (let i = 0; i < senNum; i++) {
if (sentences[i].length > 1000) {
// split sentence up and add as multiple:
sentences[i]
.split(',')
.map((p) => p.trim())
.forEach((p) => finalArray.push(p));
} else {
finalArray.push(sentences[i]);
}
}
/*
if (roll(0.1)) finalArray.push(affirmation());
*/
}
}
finalArray = finalArray.map((e, i) =>
e[e.length - 1] != '?' && i == finalArray.length - 1
? addEndSign(e.trim())
: e
);
return finalArray;
}
function addEndSign(input: string) {
return (
input +
randomChoice([
'!!',
'.',
'!',
'?',
'.',
'.',
'!?',
'??',
'...',
'.',
'.',
'.',
'.',
])
);
}
function question(input: string) {
if (roll(0.65) && input.length > 10) {
let numberOfWordsForQuestion = randomBetween(1, 5);
return (
input
.split(/[.!?\s]/)
.filter((e, i) => i < numberOfWordsForQuestion)
.join(' ') + '?'
);
} else {
// question related to input
// generic question
return affirmation();
}
}
function affirmation() {
return randomChoice([
'yeah',
'yea',
'no',
'just kidding',
'not really',
'yes wtf',
'youre right',
'no, actually not',
'no',
'naah',
'yessir',
'hahaha yes',
'absolutely',
'nah',
'uhm yes',
'I think so',
"surprising, isn't it?",
"You don't think so?",
'omg, really?',
'really?',
'Thats not good',
'I like that',
'hmmm',
'weird flex bro',
'This is not true',
'you sure?',
'Why?',
'No way!',
'Why that?',
'where though?',
'so what?',
'sure?',
'wtf?',
'Hav you seen that?',
'right now?',
'what do you think?',
'wdym?',
'lol',
'almost certainly',
'no way!?',
'me bored, can you change the topic?',
'okay',
'lets talk about something else',
'Can you say that again?',
'Wait what?',
'eehm what?',
'interesting',
'cant believe that',
'yeah yeah yeah',
'ehem',
'uhmm what?',
'not really',
'',
]);
}
I want to be able to access the "const history" outside in the historyInfo function so I don't have to call the historyInfo() function inside the selectOption function. The main problem is that there are two addEventListeners calling the showOption function where the historyInfo function is called. I just want the buyItemPanelbtn click to call the historyInfo function.
function showbrookton(brooktonIndex){
const brookton = Brookton.find(brookton => brookton.id === brooktonIndex)
textElement.innerText = brookton.text //fill text element
titleElement.innerText = brookton.title //title element
while (optionButtonsElement.firstChild) { //removes all buttons
optionButtonsElement.removeChild(optionButtonsElement.firstChild)
}
brookton.options.forEach(option => { //option is options and the funtion is performed on each option
if(showOption(option) && (option.text)) { //
const button = document.createElement('button')
button.innerText = option.text
button.classList.add('btn')
button.addEventListener('click', () => {
selectOption(option);
})
optionButtonsElement.appendChild(button)
}
if(option.backText){ //this goes back to previous page
const backOption = option.backText;
backButton.addEventListener('click', () => showbrookton(backOption))
} //else close window
})
}
function showOption(option){
return option.requiredState == null || option.requiredState(state)
}
function selectOption(option){
const nextbrooktonId = option.nextText
const history = option.historyText;
if (nextbrooktonId == "buyItem"){
buyItemPanel();
function buyItemPanel(){
const buyItemName = option.text;
buyItemPanelName.innerText = buyItemName
buyItemPanelPrice.innerText = "Price: " + option.price
buyPanelType.innerText = option.type
historyInfo(history);
showBuyItemPanel()
}
function historyInfo(history) {
$(HistoryPanel).append("<div>" + history + "</div>");
}
buyItemPanelbtn.addEventListener('click', () => selectOption());
const Brookton = [
{
id: "Bakery",
title: "Bakery",
text: 'Choose a Location to visit.',
options: [
{
text: 'Bread',
type: 'Food',
price: '$4',
historyText: "You bought bread",
nextText: "buyItem",
}
]
}
]
Declare the history variable outside as
.
var history;
and then in the selectOption function
history = option.historyText;
Code:
var history;
function selectOption(option) {
history = option.historyText;
historyInfo(history);
return showBuyItemPanel()
}
showbrookton(nextbrooktonId)
}
function historyInfo(history) {
$(HistoryPanel).append("<div>" + history + "</div>");
}
This seems to have solved the problem. I declared Newoption globally and then set it to the parameter option inside the selectOption function. I was then able to make a const 'history' inside the historyInfo function.
var Newoption;
function showOption(option){
return option.requiredState == null || option.requiredState(state)
}
function selectOption(option){
Newoption = option;
const nextbrooktonId = option.nextText
// const history = option.historyText;
if (nextbrooktonId == "buyItem"){
buyItemPanel();
function buyItemPanel(){
const buyItemName = option.text;
buyItemPanelName.innerText = buyItemName
buyItemPanelPrice.innerText = "Price: " + option.price
buyPanelType.innerText = option.type
showBuyItemPanel()
}
function historyInfo(){
const history = Newoption.historyText;
$(HistoryPanel).append("<div>" + history + "</div>");
updateScroll();
}
// click buy button
buyItemButton.addEventListener("click", () => {
closeItemBuyWindow();
closeLocationsMenu();
historyInfo();
});
I have selectedTags which holds up to 3 tags.
vm.tags Could contain thousands, most likely just hundreds of tags that I need to compare too.
If the ids of the 3 tags match the id of a tag inside of vm.tags I need to turn their borders on. There are 3 borders too: border1, border2, border3.
const tagsColorCheck = () => {
let name, selected, its_ticker;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length > 0) {
for (let i=0; i<vm.tags.length; i++) {
for (let j=0; j<selectedTags.length; j++) {
if (selectedTags[j].term_id == vm.tags[i].term_id) {
name = 'border'+ ( j + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
vm.tags[i][name] = true;
vm.tags[i][selected] = true;
vm.tags[i][its_ticker] = selectedTags[j].its_ticker;
}
}
}
}
};
So far here is what I have in process (_.each):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
_.each(vm.tags, (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
})
};
And this (for of loop):
const tagsColorCheck = () => {
let name, selected, its_ticker, vmTerm, term_1, term_2, term_3, ticker_1, ticker_2, ticker_3;
let selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
const borderRizeTag = (tag) => {
if (tag.term_id === term_1) {
tag.selected = true;
tag.border1 = true;
tag.its_ticker = ticker_1;
}
if (tag.term_id === term_2) {
tag.selected = true;
tag.border2 = true;
tag.its_ticker = ticker_2;
}
if (tag.term_id === term_3) {
tag.selected = true;
tag.border3 = true;
tag.its_ticker = ticker_3;
}
return tag;
}
if (!_.isEmpty(selectedTags)) {
vmTerm = R.findIndex(R.propEq('term_id', selectedTags[0].term_id))(vm.tags);
}
if (selectedTags[0]) { term_1 = parseInt(selectedTags[0].term_id); ticker_1 = selectedTags[0].its_ticker; }
if (selectedTags[1]) { term_2 = parseInt(selectedTags[1].term_id); ticker_2 = selectedTags[1].its_ticker; }
if (selectedTags[2]) { term_3 = parseInt(selectedTags[2].term_id); ticker_3 = selectedTags[2].its_ticker; }
for (let tag of vm.tags) {
console.log(tag);
tag = borderRizeTag(tag);
}
console.log('vmTerm',vmTerm);
};
ES6 fiddle to run: http://www.es6fiddle.net/is0prsq9/ (note, copy the entire text, and paste it inside a browser console or a node REPL, and then examine the value of tags to see the result)
It's not lodash, and you don't really need it with ES6 constructs. Relevant code:
const tagsColorCheck = () => {
let tags = TagsFactory.retrieveTickerTags('onlyTags')
sel.forEach( (s,i) =>
tags.filter(t => t.term_id === s.term_id).forEach( t => {
t['border' + (i+1)] = true
t.selected = true
t.its_ticker = s.its_ticker
})
)
return tags
}
If you were writing this in a functional language, you would have access to a list comprehension and it would be a bit cleaner. Essentially, this is a pretty clear case of (for every x in a and y in b) so a list comprehension is what you need, but you don't have it in javascript (mozilla has it, but not useful outside of that realm).
The result is a somewhat functional approach -- however, it can never really be functional in pure javascript. Possibly the most important benefit of the functional paradigm are immutable data structures where you would compose your new list. Instead, you just modify them in place here, which really is not very functional at all. Still, if you prefer the each approach to a literal incremental one, as you have done above and as I did in my post, then it's a (albeit slower but arguably cleaner) better approach.
Figured out an awesome solution! :D using both _lodash and ramda.
So below, immediately each is quicker to reason about, then using R.equals to compare if the term_ids match. Then setting the values of the keys on the correct tag object.
if (!_.isEmpty(selectedTags)) {
_.each(vm.tags, tag => {
_.each(selectedTags, (selectedTag, index) => {
let areTermIDsSame = R.equals;
if (areTermIDsSame(parseInt(selectedTag.term_id), parseInt(tag.term_id))) {
name = 'border'+ ( index + 1 );
selected = 'selected';
its_ticker = 'its_ticker';
tag[name] = true;
tag[selected] = true;
tag[its_ticker] = selectedTag.its_ticker;
}
});
})
}
The idea is simple - create an index of all tags by term_id. Iterate the selected tags. If a tag is found by id in the tags index, mutate it by assigning an object with the new properties.
btw - The only thing lodash is needed for is _.keyBy(), and you can easily do that using Array.prototype.reduce if you don't want to use lodash.
/** mocked vm **/
const vm = {
tags: [{ term_id: 1 }, { term_id: 2 }, { term_id: 3 }, { term_id: 4 }, { term_id: 5 }, { term_id: 6 }]
}
/** mocked TagsFactory **/
const TagsFactory = {
retrieveTickerTags: () => [{ term_id: 1, its_ticker: 'ticker 1' }, { term_id: 4, its_ticker: 'ticker 4' }, { term_id: 5, its_ticker: 'ticker 5' }]
};
const tagsColorCheck = () => {
const selectedTags = TagsFactory.retrieveTickerTags('onlyTags');
if (selectedTags.length === 0) { // if selectedTags is empty exit
return;
}
const vmTagsIndex = _.keyBy(vm.tags, (tag) => tag.term_id); // create an index of tags by term_id
selectedTags.forEach(({
term_id, its_ticker
}, index) => { // loop through selectd tags and retreive term_id and its_ticker from the current selected tag
const tag = vmTagsIndex[term_id]; // find the tag in the vmTagsIndex
if (!tag) { // if the id doesn't exist in vmTagsIndex exit
return;
}
Object.assign(tag, { // mutate the tag by assigining it an object with the available properties
selected: true,
[`border${index + 1}`]: true,
its_ticker
});
});
};
tagsColorCheck();
console.log(vm.tags);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
I am using SweetAlert2, and have a Select List. My challenge is that the values in the select list are added programmatically. While my code runs, the dropdown has the right NUMBER of values, the text says [object Object] rather than what I added. What am I doing wrong? Code is below.
var outputStr = [];
for (var i = 0; i < data.rows.length; i++) {
// If here, we have data, so show the information....
var vREGISTRY_ID = data.rows[i].REGISTRY_ID ? data.rows[i].REGISTRY_ID : '-';
var vNN_NAME = data.rows[i].NN_NAME ? data.rows[i].NN_NAME : '-';
var vACCOUNT_NAME = data.rows[i].ACCOUNT_NAME ? data.rows[i].ACCOUNT_NAME : '-';
var vSITE_DUNS_9DIG = data.rows[i].SITE_DUNS_9DIG ? data.rows[i].SITE_DUNS_9DIG : '-';
var vPRIMARY_CITY = data.rows[i].PRIMARY_CITY ? data.rows[i].PRIMARY_CITY : '-';
var vPRIMARY_STATE_PROVINCE = data.rows[i].PRIMARY_STATE_PROVINCE ? data.rows[i].PRIMARY_STATE_PROVINCE : '-';
outputStr.push({
value:vREGISTRY_ID,
label: vACCOUNT_NAME
}) ;
}; // end of FOR loop
swal({
title: 'Select Account Name or Division',
input: 'select',
inputOptions: outputStr ,
inputPlaceholder: 'Select from dropdown',
showCancelButton: true,
inputValidator: function(value) {
return new Promise(function(resolve, reject) {
if (value === 'abc') {
resolve();
} else {
reject('You need to select abc :)');
}
});
}
}).then(function(result) {
swal({
type: 'success',
html: 'You selected: ' + result
});
})
You have to add dynamical properties to the JavaScript object
Like this: data[propertyName] = propertyValue;
var inputOptions = {}; // Define like this!
// Instead of sample variables,
// your data handling here
var vREGISTRY_ID = "500";
var vACCOUNT_NAME = "Peter";
// Add the Variables like this
// This will create '500' : 'Peter',
inputOptions[vREGISTRY_ID] = vACCOUNT_NAME;
inputOptions["455"] = "Martin";
// Note that the options will get sorted by their value
swal({
title: 'Select Account Name or Division',
input: 'select',
inputOptions: inputOptions,
inputPlaceholder: 'Select from dropdown',
showCancelButton: true,
inputValidator: function(value) {
return new Promise(function(resolve, reject) {
if (value == "500") {
resolve();
} else {
reject('You need to select Peter :)');
}
});
}
}).then(function(result) {
swal({
type: 'success',
html: 'You selected: ' + result
});
})
<link href="https://cdn.jsdelivr.net/sweetalert2/4.1.5/sweetalert2.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/sweetalert2/4.1.5/sweetalert2.js"></script>
Let's say your 'data' is the response from an Api call and you can change the response format.Then, you can return a dictionary of this form Dictionary<int,string> and bind directly the response: inputOptions: data.
I'm new to Javascript, come from Java, this is less intuitive for me.
I would like to check for duplication of the title value and concatenate to the duplicated title the producer name
My idea is to sort the values and then check each one with is next for duplication
Can you suggest me how to implement this kind of solution?
function getItems(itemKeys, itemSortOrders, itemsMap)
{
var items = _.map(itemKeys, function(itemKey, index) {
var item = itemsMap[itemKey];
return _.extend({
key: itemKey,
title: item.title,
imageURL: item.imageURL,
formattedPrice: utils.formatMoney(item.price),
producerKey: item.producerKey,
producerTitle: item.producerTitle,
allowOrder: true,
sortOrder: itemSortOrders[index]
}, calculateItemDetails(item.deliveryDayAvailable, item.deliveryDayStatus, item.deliveryDayUsageCount));
});
items = _.compact(items);
return items;
}
Thanks
You can test if item have duplicates with this function, it use filter to find the same items and check if the length is larger then 1.
function haveDuplicates(itemKeys, itemsMap, itemKey) {
var item = itemsMap[itemKey];
var dups = itemKeys.filter(function(key) {
return itemsMap[key] == item;
});
return dups.length > 1;
}
var itemsMap = {
'foo': 'Lorem',
'bar': 'Lorem',
'baz': 'Ipsum',
'quux': 'Dolor'
};
var output = document.getElementById('output');
var itemKeys = Object.keys(itemsMap);
itemKeys.map(function(key) {
output.innerHTML += itemsMap[key] + ' ' +
(haveDuplicates(itemKeys, itemsMap, key) ? 'have' : 'don\'t have') + '\n';
});
<pre id="output"></pre>
SO this is what i did eventually and this worked
var duplicateMap = {};
_.each(itemsMap, function(item) {
var title = item.title.trim();
if (duplicateMap[title]) {
duplicateMap[title] = 2;
}
else {
duplicateMap[title] = 1;
}
});