I have looked at previous answers but cannot find a solution.
My state contains a deck of "color cards":
class App extends Component {
constructor() {
super()
this.allCards = ['#fca7f3 ', 'white', ' #6da740 ',' #f6faba ', ' #ccc5c1 ', ' #f7791f ', ' #575657 ', ' #03faf5 ', ' #13afdb ', ' #7509e2 ', ' #63522e ', ' #d809e2 ', '#060606', '#fd2f03',' #effa17 ',' #33fb2d ']
this.state = {currentDeck: [' #ccc5c1 ', ' #f7791f ', ' #575657 ', ' #03faf5 ',]}
}
This is updated with this function:
changeDifficulty = (e) => {
let newDeck = []
let howManyCards = e.target.value // this decides difficulty level
for (let i = 0; i < howManyCards; i++) {
newDeck.push(this.allCards[i])
}
this.setState({currentDeck: newDeck})
}
The state is successfully updating, however, the component below is not re-rendering after the first render:
<Game deck={this.state.currentDeck} />
So the number of cards on the screen remains the same as the default setting.
If I console.log newDeck before setting state, it shows the following, first after clicking Medium button, then after Hard.
Array(8) [ "#fca7f3 ", "white", " #6da740 ", " #f6faba ", " #ccc5c1 ", " #f7791f ", " #575657 ", " #03faf5 " ]
Array(12) [ "#fca7f3 ", "white", " #6da740 ", " #f6faba ", " #ccc5c1 ", " #f7791f ", " #575657 ", " #03faf5 ", " #13afdb ", " #7509e2 ", … ]
Your array reference is not updated in state when you write this,
this.setState({currentDeck: newDeck})
As the reference is not updated react renderer doesn't know about the update. What you need to do is create a new array and push that in state like this,
this.setState({currentDeck: [...newDeck]})
Related
hope everyone is fine, I have a tricky question, from an RPA app I get this object:
let data = {
Fecha: '2022-12-14T00:00:00',
Hora: '1899-12-31T16:14:00',
'Aten.': 73,
' Nro Ing ': 0,
Cerrada: 'S',
' ': ' ',
' Nombre Atenci¾n ': 'AMBULATORIA',
'EstadoHC.Electronica': ' - ',
Profesional: ' GARCIA CHAVERRA MADELEINE ',
Especialidad: ' MEDICINA GENERAL ',
Diagnostico: ' ENFERMEDAD CARDIACA, NO ESPECIFICADA ',
'Num.Cta': 0
}
As you can see, the key of the object, some of them are a little weird, what i want to do is replace the single quotes from the keys, to get the [Nombre Atenci¾n] value.
What I try is parser the object in a new object with JSON.parse and replace the spaces in the beginning and the end, like this:
let data2 = JSON.parse(JSON.stringify(data).replace(/"\s+|\s+"/g,'"'));
Then I try to iterate the second object, to get the specific value of the key mentioned before, after replace spaces and characters, but then I get undefined instead of "AMBULATORIA"
for(let dat in data2){
dat = dat.replace(/\s\s+/g, '').replace("¾", 'o');
console.log(dat.NombreAtencion)
}
Why I use a for to iterate "one single object" is because I get an array of objects like that one, so I have to use the same treatment to every object.
As you can see, the key of the object, some of them are a little weird, what i want to do is replace the single quotes from the keys
There are no single quotes in the object keys. In an object literal, you can put the name of the property in quotes (single or double). The quotes are just delimiters, not part of the property name. You only have to do that if the property name contains a character that isn't allowed in a property literal (which is true of all of your examples — spaces and . are perfectly valid in property names, but not property name literals).
So there's nothing to do, your object already has property names that don't have those quotes in them. You can tell by looking at the property names:
let data = {
Fecha: '2022-12-14T00:00:00',
Hora: '1899-12-31T16:14:00',
'Aten.': 73,
' Nro Ing ': 0,
Cerrada: 'S',
' ': ' ',
' Nombre Atenci¾n ': 'AMBULATORIA',
'EstadoHC.Electronica': ' - ',
Profesional: ' GARCIA CHAVERRA MADELEINE ',
Especialidad: ' MEDICINA GENERAL ',
Diagnostico: ' ENFERMEDAD CARDIACA, NO ESPECIFICADA ',
'Num.Cta': 0
};
console.log("Property names:");
for (const name of Object.keys(data)) {
console.log(name);
}
console.log("Value of property Aten.: ", data["Aten."]);
.as-console-wrapper {
max-height: 100% !important;
}
If you want to rationalize those property names so they're things you can use in property name literals (and so they follow the standard conventions for JavaScript property names), you could have a Map with the original name and the new name you'd like to use, and then create a new object with the new names for the properties:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
const nameMap = new Map([
["Fecha", "fecha"],
["Hora", "hora"],
["Aten.", "aten"],
[" Nro Ing ", "norIng"],
["Cerrada", "cerrada"],
[" ", "spaces"], // Or whatever
[" Nombre Atenci¾n ", "nombreAtencion"],
["EstadoHC.Electronica", "estadoHCElectronica"],
["Profesional", "profesional"],
["Especialidad", "especialidad"],
["Diagnostico", "diagnostico"],
["Num.Cta", "numCta"],
]);
const updated = Object.fromEntries(
Object.entries(data).map(([name, value]) => [nameMap.get(name) ?? name, value])
);
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or using a simple loop instead of Object.fromEntries, Object.entries, and map:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
const nameMap = new Map([
["Fecha", "fecha"],
["Hora", "hora"],
["Aten.", "aten"],
[" Nro Ing ", "norIng"],
["Cerrada", "cerrada"],
[" ", "spaces"], // Or whatever
[" Nombre Atenci¾n ", "nombreAtencion"],
["EstadoHC.Electronica", "estadoHCElectronica"],
["Profesional", "profesional"],
["Especialidad", "especialidad"],
["Diagnostico", "diagnostico"],
["Num.Cta", "numCta"],
]);
const updated = {};
for (const name of Object.keys(data)) {
const newName = nameMap.get(name) ?? name;
updated[newName] = data[name];
}
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or if you want to do it with some rules, here's an example treating . as a space, removing extraneous spaces, and converting to standard camelCase:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
function convertName(name) {
// Convert anything that isn't A-Za-z0-9_ to a space,
// and trim any leading/trailing spaces
name = name.replace(/[^\w]/g, " ").trim();
// If blank, bail early
if (!name) {
return "__unkown__";
}
// Split into words at a series of spaceds
let words = name.split(/ +/);
// Make the first word all lower-case, and make remaining words lower
// case except the first letter
words[0] = words[0].toLowerCase();
for (let n = 1; n < words.length; ++n) {
words[n] = words[n][0].toUpperCase() + words[0].substring(1).toLowerCase();
}
// Join the result
return words.join("");
}
const updated = Object.fromEntries(
Object.entries(data).map(([name, value]) => [convertName(name), value])
);
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
Or (again) using a simple loop instead of Object.fromEntries, Object.entries, and map:
let data = {
Fecha: "2022-12-14T00:00:00",
Hora: "1899-12-31T16:14:00",
"Aten.": 73,
" Nro Ing ": 0,
Cerrada: "S",
" ": " ",
" Nombre Atenci¾n ": "AMBULATORIA",
"EstadoHC.Electronica": " - ",
Profesional: " GARCIA CHAVERRA MADELEINE ",
Especialidad: " MEDICINA GENERAL ",
Diagnostico: " ENFERMEDAD CARDIACA, NO ESPECIFICADA ",
"Num.Cta": 0,
};
function convertName(name) {
// Convert anything that isn't A-Za-z0-9_ to a space,
// and trim any leading/trailing spaces
name = name.replace(/[^\w]/g, " ").trim();
// If blank, bail early
if (!name) {
return "__unkown__";
}
// Split into words at a series of spaceds
let words = name.split(/ +/);
// Make the first word all lower-case, and make remaining words lower
// case except the first letter
words[0] = words[0].toLowerCase();
for (let n = 1; n < words.length; ++n) {
words[n] = words[n][0].toUpperCase() + words[0].substring(1).toLowerCase();
}
// Join the result
return words.join("");
}
const updated = {};
for (const name of Object.keys(data)) {
const newName = convertName(name);
updated[newName] = data[name];
}
console.log(updated);
.as-console-wrapper {
max-height: 100% !important;
}
I'm working with the Twitter API and I'm trying to get only the first news of a tweet and its link. If I console.log tweetNews I get something like this as example:
{
text: 'exampletext. \n' +
'\n' +
'exampletext. \n' +
'\n' +
'https://examplelink',
href: 'https://examplelink
},
I would like to get only the first string of the text, removing also the link inside the text.
Down below the rest of my code:
module.exports.filterTweets = (parsedArray) => {
const filteredTweets = parsedArray.filter(
(tweet) => tweet.entities.urls.length === 1
);
const tweetNews = filteredTweets.map((x) => {
return { text: x.full_text, href: x.entities.urls[0].url };
});
console.log("tweetNews", tweetNews);
return tweetNews;
};
I'm not sure I 100% follow what you are asking for, but this should get you on your way. This shows how to get the first part of the string (up to the first line break), and how to remove (http/https) URLs:
function cleanInput(input){
let firstLine = input.split(/\s+\n\s+/)[0]
//this regex is overly simplistic, just for demo purposes
//see more complete example at https://stackoverflow.com/a/3809435/57624
let withoutURL = firstLine.replace (/http[s]?:\/\/[a-z./]+/i, '');
return withoutURL
}
let sampleData1 = {
text: 'exampletext. \n' +
'\n' +
'exampletext. \n' +
'\n' +
'https://examplelink',
href: 'https://examplelink'
};
let sampleResult1 = cleanInput(sampleData1.text)
console.log("result 1: " + sampleResult1)
let sampleData2 = {
text: 'A URL: https://examplelink.com \n' +
'\n' +
'exampletext. \n' +
'\n' +
'more',
href: 'https://examplelink'
};
let sampleResult2 = cleanInput(sampleData2.text)
console.log("result 2: " + sampleResult2)
I'm trying to take a JSON Array and display the full output, but nicely formatted. (see commented out section) Unfortunately the JSON array returns back with OBJECT then its output. So I stringify to fix the [Object, Object] error I was getting. But now everything is on one line. How do iterate through the array and put them on new lines?
Second issue I'm having is, I can't do 3 of the same functions as you notice in the uncommented section. I'd like to take each result and add a new line in between them.
function setTitleStatus(context, settings) {
$SD.api.setTitle(context, "Updating...");
getResults(result => resultCallback(result, context));
}
function resultCallback(result, context) {
if (!result.hasOwnProperty("Object")) {
$SD.api.setTitle(context, JSON.stringify(result));
console.log(JSON.stringify(result, '%c%s'));
return;
}
// This is where I'd like all 3 objects to be split on new lines.
// $SD.api.setTitle(context, result.Platform.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.Platform + " ")
// $SD.api.setTitle(context, result.PU.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.PU + " ")
// $SD.api.setTitle(context, result.EA.replace(new RegExp(' ', 'g'), '\n') +
// "\n" + result.EA + " ")
}
function getResults(updateTitleFn) {
let endPoint = "https://status.robertsspaceindustries.com/static/content/api/v0/systems.en.json";
$.getJSON(endPoint)
.done(function (response) {
updateTitleFn({
"Platform": response[0].status,
"PU": response[1].status,
"EA": response[2].status,
});
console.log("Platform", response[0].status)
console.log("PU", response[1].status)
console.log("EA", response[2].status)
})
}
Update
If I uncomment the sections this is what it shows. Its hard to tell but whats happening is, its taking replacing setTitle three times, and taking the last line. $SD.api.setTitle(context, result.EA.replace(new RegExp(' ', 'g'), '\n') +
"\n" + result.EA + " ")
Via Screenshot
To get nicely formatted output from JSON.stringify, supply the optional arguments:
JSON.stringify(obj, null, 2)
let arr = ["Pineapple", "Lemon", "Apple", "Orange", "Peach"];
document.getElementById('result').innerHTML =
'Stringify default: ' + JSON.stringify(arr) + '\n\n' +
'Stringify formatted: ' + JSON.stringify(arr, null, 2);
<pre id="result"></pre>
How do I do an update statement with knex.js where the returning data comes from more than one table. For example, how would I write this update query with knex.js?
update notes
set note = 'This is an updated1 note', timestamp = now()
from(select
id,
note,
user_id,
customer_id
from notes
where id = '46' AND user_id = 7) a
left join customers as b on a.customer_id = b.id
where notes.id = a.id
returning a.id, a.note, a.user_id, b.id;
I can write it to return data when only one table is used:
knex('notes')
.returning([
'notes.id',
'notes.note',
'notes.user_id AS userId',
'notes.customer_id AS customerId',
'notes.product_id AS productId',
'notes.timestamp',
])
.where('notes.id', noteId)
.update({
timestamp: new Date(),
note: req.body.note,
});
My problems start when I then try to introduce customers.
I also tried this:
const [note] = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, a.note, a.user_id, b.id', ['This is an updated1 note', 46]
);
but it gives me TypeError: (intermediate value) is not iterable.
UPDATE
I've now got this:
let note = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id, '
+ 'product_id, '
+ 'timestamp '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'LEFT JOIN products AS c ON a.product_id = c.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, a.note, a.user_id AS userId, a.customer_id AS customerId, a.product_id AS productId, a.timestamp, b.title AS customerName, b.code AS customerCode, c.title AS productName, c.code AS productCode', [req.body.note, noteId]
);
/*const [note] = await db.sequelize.knex('notes')
.returning([
'notes.id',
'notes.note',
'notes.user_id AS userId',
'notes.customer_id AS customerId',
'notes.product_id AS productId',
'notes.timestamp',
//'customers.title AS customerName',
//'customers.code AS customerCode',
//'products.title AS productName',
//'products.code AS productCode',
])
//.leftJoin('customers', 'notes.customer_id', 'customers.id')
//.leftJoin('products', 'notes.product_id', 'products.id')
.where('notes.id', noteId)
.update({
timestamp: new Date(),
note: req.body.note,
});*/
console.log('PC NOTE', note.rows);
[note] = note.rows;
return res.json({ note });
It returns this:
{
"note": {
"id": 46,
"note": "This is an updated2 note",
"userid": 7,
"customerid": 111781,
"productid": null,
"timestamp": "2019-07-12T19:37:23.996Z",
"customername": "PC CUSTOMER3",
"customercode": "PC003",
"productname": null,
"productcode": null
}
}
This is almost what I need except the returned keys are all lower case. How do I get userid, customerid, productid, customername, customercode, productname and productcode to appear in camel case like I stated in the RETURN part on my knex statement?
Knex doesn't have any special support for update + joins
https://github.com/tgriesser/knex/issues/2796
so writing raw query is your only choice.
This is what worked for me:
let note = await db.sequelize.knex.raw(
'UPDATE notes '
+ 'SET note = ?, '
+ 'timestamp = NOW() '
+ 'FROM(SELECT id, '
+ 'note, '
+ 'user_id, '
+ 'customer_id, '
+ 'product_id, '
+ 'timestamp '
+ 'FROM notes '
+ 'WHERE id = ? '
+ 'AND user_id = 7) AS a '
+ 'LEFT JOIN customers AS b ON a.customer_id = b.id '
+ 'LEFT JOIN products AS c ON a.product_id = c.id '
+ 'WHERE notes.id = a.id '
+ 'RETURNING a.id, '
+ 'notes.note, '
+ 'notes.user_id AS "userId", '
+ 'notes.customer_id AS "customerId", '
+ 'notes.product_id AS "productId", '
+ 'notes.timestamp, '
+ 'b.title AS "customerName", '
+ 'b.code AS "customerCode", '
+ 'c.title AS "productName", '
+ 'c.code AS "productCode"', [newNote, noteId],
);
[note] = note.rows;
return res.json({ note });
i'm able to parse in and display data for all pieces of my code except in this line
" where: " + e.gd$where.valueString + // < this line is displaying undefined
here is the code block that is doing the processing. everything else displays correct data
Titanium.API.info(cal.feed.entry.length);
var i;
for (i=0; i < cal.feed.entry.length; i++){
var e = cal.feed.entry[i];
Titanium.API.info("title: " + e.title.$t +
" content " + e.content.$t +
" when: " + e.gd$when[0].startTime + " - " + e.gd$when[0].endTime +
" evenstatus" + e.gd$eventStatus.value +
" where: " + e.gd$where.valueString + // < this line is displaying undefined
" gcal$uid: " + e.gCal$uid.value
);
here is what should be displayed from the calendar
"gd$where": [{
"valueString": "Any of the 11 elementary schools"
}],
gd$where is an array of objects. In order to access "valueString" in the first key, you need to access it from within that object, like so:
gd$where[0].valueString