//global variable
var memArray =[];
//object
function member(id, password){
this.id = id;
this.pwd = password
}
var memObj1=new member("m001","123");
memArray.push(memObj1);
How do I send out an alert to prompt and edit each object that is push to memArray?
if you want to customize it try to use your own modals instead of window.prompt and just display values with editable text fields, on submit capture those values and change them in array respectively.
var memArray = [];
//object
function member(id, password) {
this.id = id;
this.pwd = password
}
var memObj1 = new member("m001", "123");
var memObj2 = new member("m002", "123");
var memObj3 = new member("m031", "123");
memArray.push(memObj1);
memArray.push(memObj2);
memArray.push(memObj3);
memArray.forEach((val, ind) => {
memArray[ind] = JSON.parse(window.prompt("want to edit values?", JSON.stringify(memArray[ind])));
});
console.log(memArray)
Pavan's answer is good, but to make this testable in automated tests:
// I would name these fields in your API
// by making the constructor take an object.
// Capitalise the name to signal that it can be newed
function Member({id, password}) {
this.id = id;
this.pwd = password
}
// Name the array for what it is
const members = [
new Member({id: "m001", password: "123"}),
new Member({id: "m002", password: "123"}),
new Member({id: "m031", password: "123"})
]
const editInBrowserFn = member => JSON.parse(window.prompt("want to edit values?", JSON.stringify(member)));
const updateMembers = editFn => array => array.map(editFn)
// To get an update
const updatedMembers = updateMembers(editInBrowserFn)(members)
console.log(updatedMembers)
// You can now test it by making an testing editFn that doesn't need user interaction
const testEditFn = m => new Member({id: m.id, password: 'test'})
const testMembers = updateMembers(testEditFn)(members)
console.log(testMembers)
See this article for an in-depth explanation of this approach.
To do it this way, you will need to take it out of the global scope. That is a good discipline to develop. As a first step you could make an object in global scope that holds the latest member list:
const Members = (() => {
let _members = []
return {
setMembers: members => _members = [...members],
getMembers: () => [..._members]
}
})()
Now the way to update the members is like this:
const updateFn = updateMembers(editInBrowser)
function updatePasswords() {
const members = Members.getMembers()
Members.setMembers(updateFn(members))
}
Nothing can accidentally delete or mutate the members array now, so that bug surface area is eliminated.
This is how React setState is designed. It's inspired by functional programming ideas and immutability.
You probably want to be able to update just one member, so:
const Members = (() => {
let _members = []
return {
setMembers: members => _members = [...members],
getMembers: () => [..._members],
updateMember: updated =>
this.members = _members.map(m =>
m.id === updated.id ? updated : m)
}
})()
Now all your array mutation is in one single place, and you only have to make it bug-free there. Otherwise, your global state is exposed and you have to fix bugs everywhere related to it. Without this, all your calling functions are responsibly for correctly managing the global state of the application. Complex.
Crystallise the complexity in one place.
I wrote an article and a complete implementation of the store (in 40 lines of code) here.
As far as I concern, alerts are just models on the browser to provide informative feedback to a particular user on his actions. Therefore, I think it is required to use either a dialog model or a form to edit the objects in the memArray.
Related
actually this code works as expected but, if I do input a different userId, it still do overwrite the existing user (not the file) and the ideia was to add another one
const user = userId;
const userObj = {[user]:valueX};
words.users = userObj;
fs.writeFileSync('words.json', JSON.stringify(words,null,2), finished);
input comes from here (readline-sync)
let userId = input.question('Enter yourUserId: ');
and yes i'm reading the file first
let words = JSON.parse(fs.readFileSync('words.json'));
const userObj = {[user]:valueX};
words.users = userObj;
The object you assign to words.users needs to include all the existing users and not just your new one.
const userObj = {...words.users, [user]:valueX };
From your code it looks like words.users is an object and in that case
if(!words.users) words.users = {}; // Make sure the words users are created
words.users[user] = valueX;
This would give you an words.users object that look like this
{user1: valueX1, user2: valueX2}
And you could access like this
console.log(words.users[user1]); // valueX1
Within my function, through interaction from the user, I aim slowly build up an array of responses which I then pass off to an API. However, different approaches to append to the array, simply return a single position array (overwrite).
My current code as follows:
const contribution: Array = [];
const handlePress = () => {
var col = {
response,
user: 1,
update: update.id,
question: q.id,
};
contribution = [...contribution, col];
}
My understanding is that contribution = [...contribution, col] is the correct way to add to the array.
What is the best practice approach for doing this inside a function called each time the user interacts?
Although it is not clear from the question, I suspect, this code is inside a component. If so, then a new contribution array is created on every render. You need to use useState to store this array so that a new array is not created on every render.
const [contribution, setContribution] = React.useState([]);
const handlePress = () => {
var col = {
response,
user: 1,
update: update.id,
question: q.id,
};
setContribution([...contribution, col]);
}
I'm creating a page object model and one of the properties is all the users from a table. The table has a few columns so I'd like to parse that table and create a user object for each row, then return that set to then be used in tests. So far, this is what that property of my page object looks like:
users: {
get: function() {
let userRecords = [];
var users = element.all(by.repeater('user in users')).each(function(tr, index) {
let user = {
name: tr.element(by.css('td:nth-child(2)')).getText().then(text => {return text;}),
role: tr.element(by.css('td:nth-child(3)')).getText().then(text => {expect(text).toBeTruthy();}),
status: tr.element(by.css('td:nth-child(4)')).getText().then(text => {expect(text).toBeTruthy();}),
//actionsButton: tr.element(by.css('btn btn-default'))
};
userRecords += user;
}).then(userRecords => {return userRecords});
return userRecords;
}
},
Through trial and error I encounter one of two outcomes when just trying to print to screen each element of userRecords:
each element prints as undefined or
userRecords is not defined.
Just to reiterate, I'm simply trying to build an array that holds each user as an object to then be able to iterate / filter on that set in my tests.
Given the approach I'm taking, what's the ideal way to construct this user array and resolve the promises?
Edit: it's worth noting that if I do a console.log() within each of the getText().then() statements, it does print the correct data from the table. So, I do know that it's reading the table correctly.
I'd go with a method that returns json, and would make it async
users: async function() {
let userRecords = [];
var users = element.all(by.repeater('user in users'));
for (let i = 0; i < await users.count(); i++) {
let tr = users.get(i);
let user = {
name: await tr.element(by.css('td:nth-child(2)')).getText(),
role: await tr.element(by.css('td:nth-child(3)')).getText(),
status: await tr.element(by.css('td:nth-child(4)')).getText()
};
userRecords.push()
}
return userRecords;
},
and then use:
console.log(
JSON.stringify(
await constructorName.users()
)
)
should be as simple as that. Note, I didn't test the code, but I did use the approach in my experience. So it may require some minor modifications
In general, try to avoid .then - async/await is easier to use, .each - go with for loop instead. Also userRecords += user; doesn't do what you think it does (though I may be wrong here)
I'm trying to update an object in an array which is in my state.
I have an array of objects 'this.state.webs' which is presented in multiple div`s on a page. Each one has an onclick method which send the object to a function, then I do an API call and returns a set of 'sub webs' which I want to add to the object in the property 'subs'.
My state:
this.state = {
webs: this.props.webs
}
My template:
<Nav
groups={[
{
links: this.state.webs
}
]}
expandedStateText={'expanded'}
collapsedStateText={'collapsed'}
selectedKey={'key3'}
onLinkClick={this._openWeb.bind(this)}
/>
Onclick function:
private async _openWeb(r, n): Promise<void> {
const service = new MyService();
var subs = await service.getSubs(n);
n.subs = subs;
### How do I update 'n' with the subs? setState({ ? })
}
So, when a user clicks a web, I am fetching some sub webs and then I want to update the parent object n with the children (subs).
You can update your webs array with everything before n, a clone of n with the updated subs, and everything after n:
private async _openWeb(r, n): Promise<void> {
const service = new MyService();
const subs = await service.getSubs(n);
const { webs } = this.state;
const nIndex = webs.indexOf(n);
this.setState({
webs: [
...webs.slice(0, nIndex),
{ ...n, subs },
...webs.slice(nIndex + 1)
]
})
}
Based on the answer from Tholle and Filip W, I came up with my own approach.
Gladly to recieve some comments if this approach isn't recommended, but I find it easier to understand than the suggestion from Tholle.
const webs = [...this.state.webs];
const index = webs.indexOf(n);
webs[index].links = links;
webs[index].isExpanded = true;
this.setState({webs})
From my experiences with presenting array of data it was useful to also send an index of the targeted object (or div where click happened).
So something like this could be useful:
const webs = this.state.webs
webs[index].subs = subs
this.setState({webs})
is it possible in deepstream to subscribe to data using a list? it appears that changes to the data does not trip the subscribe() function, only something like an addEntry() appears to affect the list subscription.
const deepstream = require('deepstream.io-client-js') ;
const util = require('util') ;
const client = deepstream('localhost:6020').login();
var obj_1 = { 'sequelizeName':'Mark', 'sequelizeAddr':'123 Elm Lane' , 'sequelizeId':'1111'};
var obj_2 = { 'sequelizeName':'Lori', 'sequelizeAddr':'948 Maple Street' , 'sequelizeId':'2222'};
const rec_1 = client.record.getRecord('obj_one');
const rec_2 = client.record.getRecord('obj_two');
rec_1.set(obj_1);
rec_2.set(obj_2);
var listTest = client.record.getList('listTest');
listTest.setEntries( ['obj_one' ,'obj_two' ] );
listTest.subscribe( (result) => {
console.log('LIST SUBSCRIBE: ' + util.inspect(result));
})
setTimeout( () => {
obj_1.sequelizeAddr = '321 New Address';
rec_1.set(obj_1); // how can this change show up in the list subscribe?
}, 2000 );
I have been encouraged to try a new approach using lists, but I am unclear how to subscribe to changes in the data itself using a list, except to somehow have some sort of "generic" or "global" subscribe, which i am not sure is even possible.
Or is there some way I can subscribe using an anonymous record?
Lists are just arrays of strings. Your list content is not connected to the actual record. You can't even assume that a list entry is a record name. You would need to subscribe to each record name in a list manually to get its content updates.
this suggestion was made by both wolfram and phillipp:
class User{
constructor( recordName ) {
this.record = ds.record.getRecord( recordName );
this.record.subscribe( this._processUpdate.bind( this ) );
}
_processUpdate( data ) {
if( this.record.name === '...') {
// do stuff
}
}
}
this works great. thank you both.