Form Submit Iterating for Existing Username React - reactjs

I'm trying to create a sign up page where it first iterates through existing accounts and submits when input account is available; otherwise, it returns an error message if just one element matches.
I first tried .map, but it iterates through the entire array and still submits if one value is false. I then tried .find, but still produces the same result. Afterwards, I tried switch, case and could only return the proper outcome with ==. Lastly, I tried .find and .map using .includes but, again, no luck.
function handleSubmit(e) {
e.preventDefault();
accounts.find(acc => {
if (acc.username.includes(formData.username)) {
console.log("taken");
} else {
some post request code
}
How can I create a function that only produces one outcome if one of many elements meets the condition? Thanks for the help

You should assign the function that finds or filters the username to a variable and then create an if statement using that variable.
To return the first matching object in the array of accounts
const matchingAccount = accounts.find(account => account.username.includes(formData.username);
To return an array of matching account objects
const matchingAccounts = accounts.filter(account => account.username.includes(formData.username);

Related

Showing the new row in react-table on the current page

I have been playing with ReactTable v7 for a while and have encountered the following problem: when the table is sorted and uses paginator sometimes adding (or editing) a row causes it to be outside the current page.
You can see the problem here:
https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-kitchen-sink
Sort the table by First Name
Press add
Enter a record with First Name "zzzzz"
The record is added but is currently hidden which confuses users.
Is there a "standard" way to fix the issue? Am I missing something?
In v6 I have done a workaround for it:
React.useEffect(() => {
if (editedElementId && reactTable) {
const { data } = reactTable.props;
if (data && data.length > 0) {
const internal = reactTable.getResolvedState();
let position = -1;
internal.sortedData.forEach((row, i) => {
if (row._original.id === editedElementId) position = i;
});
if (position >= 0) {
const pageNumber = Math.floor(position / pageSize);
setPage(pageNumber);
} else {
alert.info("Element not visible");
}
}
}
}, [editedElementId]);
...
<ReactTable
ref={(r) => {setReactTable(r);}}
...
But maybe there is a bulit-in way to achieve it?
There is not currently a way to only sort the elements which are currently being displayed, no.
React Table v7's useSortBy hook sorts the entirety of the input data array, so sorting by First Name descending (A->Z) naturally places 'ZZZZZZ' at the end of the list, which will be hidden due to pagination. The v7 way of doing it would probably be similar to what you are doing already, using the exposed properties from the useTable hook instead of reactTable.resolvedState() and etc. Another way to do it would be to write your own custom sortBy method and only sort the items [0...n] where n is the number of currently displayed items.
As a side note, since the autoResetSortBy property is true by default in the example you linked, the step of sorting on First Name is irrelevant -- since the function which adds a new user to the list mutates the data array, the sorting method is reset. That function appends the new user to the end of the list, so it will always be on a new page, even if the "Rows per page" option is set to "All". Both issues can be fixed by setting autoResetSortBy to false, and changing the pageSize in addUserHandler.

How to check the value of a dropdown?

I am trying to read (using protractor and BDD) the default values of certain dropdowns. To do this, I have tried several lines of code but none of them works.
Here is the code that I am using, the console.log is not being executed for some reason. Why?
checkDropdownAssignment: function(dropdown,defaultValue) //Function to check the value assigned to a dropdown
{
let texto=[];
$$('* option:checked').each(function(element, index) { // Execute this operation for each element of the website
element.getText().then(function (text) { //Get text of the element in order to compare it with the endpoint afterwards.
texto.push(index.toString()); // Add one more component to the vector
texto[index]=text; // Save the text in a variable visible outside of this function.
console.log(texto[index]);
});
});
},
Thanks in advance.
Try this:
$$('*option:checked').all(by.tagName('option')).getAttribute('label').then(function(value){
for (var i=0; i<value.length; i++){
expect(value).toContain(arayOfExpectedResults[i]);
}
});
Here you get an array with all the labels inside the dropdown and compare them with the expected result, or use the array the way you want.

Handle null username in React Native

I have a review section in my app which uses the user's username as the heading along with their review. Everything works well unless the user does not have a username set up yet. I am trying to create a condition where if the user does not have a username set, it will be Anonymous.
I am using Redux to add the reviews.
Here is my code where I dispatch my action along with the username, uid, and review to the action creator:
const review = this.props.review.review;
//const username = this.props.userData.username.username;
const uid = this.props.string.uid;
const username = () => {
if (!this.props.userData.username.username) {
return 'Anonymous';
}
return this.props.userData.username.username;
};
//dispatch action with my values
this.props.submitUserReview({ review, username, uid });
I appreciate any help and guidance with this issue. Cheers!
SOLVED:
I solved this by using lodash thanks to Noah Allen:
const username = _.get(userData, 'username.username', 'Anonymous')
Edit: Lodash one-liner:
const username = _.get(userData, 'username.username', 'Anonymous')
To fix your example, you really only need to add a pair of parenthesis (explanation below):
this.props.submitUserReview({ review, username: username(), uid });
Taking it a step further you should do this to help improve code readability, re-use, and abstraction:
function checkUsername (userData) {
// Checks for undefined, null, and a string with no characters:
if (userData && userData.username && userData.username.username && username.length > 0) {
return userData.username.username
}
// Default case:
return 'Anonymous'
}
Then in your component:
this.props.submitUserReview({ review, username: checkUsername(this.props.userData), uid })
Basically you were passing the function username to your submission, rather than running the function and passing the result of the function to submission. In this example, you define the check username function elsewhere to help with abstraction. And then in your submission you run the function and pass the result of it to your submitUserReview function.
Note that in JS, when you have a function:const x = () => 1, the type of x will be a function. As soon as you use the parenthesis, the function gets called: x(), and the value is returned. So in your original example, you were passing x as a parameter - which means that it was never evaluated and you passed a function into your store. You need to get the value out of it and pass that to redux.
This is good to know when binding a function to a component too. For example:
<Button onPress={this.doSomething()} />. In this case, the function doSomething will get evaluated when the Button is loaded, when you really want to evaluate it when it is tapped, like so: Button onPress={this.doSomething} />. In this case, onPress evaluates the function, so you don't need to do it yourself.
Another way to solve your problem is in the component where you render the username:
<Text>{review.username ? review.username : 'Anonymous'}</Text>
That conditionally shows username if it exists in a review object (or however it looks in your component), and shows Anonymous otherwise. This might be helpful if you need to tell whether or not the review actually has a username somewhere else.
You do not need to create funcion for this small thing. You can write it in below fashion:
this.props.submitUserReview({ review, username: (this.props.userData.username.username || "Anonymous"), uid });
Here if value of this.props.userData.username.username is falsy i.e. null OR undefined OR empty string then it will pass Anonymous as a parameter. Hence it will solve your usecase.

Mongo query returns empty array on initial run

I have a collection named People that holds multiple documents. I am using Meteor JS for my website. When I run People.find({status: "Pending"}) it initially returns an empty array. If I wrap it in a Tracker.autorun:
Tracker.autorun(function(){
var peeps = People.find({status: "Pending"})
Session.set('listo', peeps)
console.log(peeps)
})
It finds the documents after first returning an empty array.
// => []
// => [{}]
The issue is that the first value (the empty array) is getting passed to my template and it is displaying none of the documents. I am using react for rendering:
render() {
return (
{
Session.get('listo').map((item) => {
HTML HERE
})
)
}
I thought that a session variable would work for this case but maybe this is conflicting with react or something, I'm not really sure.
To clarify the problem, the data always eventually gets loaded into the the listo session variable but this new data is not displayed in the render() function.

Display content of an Array of Objects with Interpolation in Angular2 Typescript

Application
A simple Search bar and a button where user enters a keyword and the response returned is from a RESTful server (HTTP GET requests)
simplesearch.ts
export class SimpleSearch {
kw: string; // keyword
resp: string; // response from Server
}
simplesearch.service.ts
Has a simple method called searchData which does a HTTP GET request with the user's keyword as a query search. (Code not included for brevity)
simplesearch.component.ts
/*All respective headers and #Component removed from brevity*/
const OUTPUT: SimpleSearch[] = []; // create an array for storing Objects
export class SimpleSearchComponent {
Output = OUTPUT; // define variable for array
constructor(private httpServ: SimpleSearchService, private temp: SimpleSearch) {}
/*Search button on HTML file does this*/
Search(inputVal: string) {
this.temp.kw = inputVal; // store the value of user's input
this.httpServ.searchData(inputVal)
.then(res => this.temp.resp = res); // store the response in temp.resp
// push the Object on the Output Array
this.Output.push({kw: this.temp.kw, resp: this.temp.resp});
}
}
Interpolation Variable
I use Output as an Interpolation Variable for my HTML template. I show the data in an unordered list
<ul>
<li *ngFor="let keyword of Output">
<span>{{keyword.kw}}</span>
</li>
</ul>
Response:
<ul>
<li *ngFor="let answer of Output">
<span>{{answer.resp}}</span> <!-- WHAT TO DO HERE for Array Index-->
</li>
</ul>
Result
I can see the keywords in a list every time a user inputs new keywords but
the responses in the wrong way
How do I pass Indexing with the Interpolation? Or am I thinking wrong?
The easy way out was to create two separate Array<String> for keywords and responses and this works great since I can use the index to delete the contents on the page too but with an Object in an Array I am confused with the key: value representation and the index of the Array (OUTPUT) itself.
The problem lies exactly where developer noticed, this.temp.resp is outside the async function. So when you are pushing items in your Output array, it's always pushing the previous search with the new keyword, therefore you are getting the behavior that the resp is always "one step behind". You can check this to understand this async behavior: How do I return the response from an Observable/http/async call in angular2?
So let's look at the code and explain what is happening. I assume you have initialized 'temp' since it isn't throwing an error on first search, where temp.resp would be undefined unless temp is initialized.
this.httpServ.searchData(inputVal)
// this takes some time to execute, so the code below this is executed before 'this.temp.resp' has received a (new) value.
.then(res => this.temp.resp = res);
// old value of 'temp.resp' will be pushed, or if it's a first search, empty value will be pushed
this.Output.push({kw: this.temp.kw, resp: this.temp.resp});
So how to solve this, would be to move the this.Output.push(... line inside the callback (then), so that the correct values will be pushed to the array.
Also I'd change your model to be an Interface instead of Class. But as to how to change the function and do the assignment inside the callback, I'd also shorten the code a bit and do:
Search(inputVal: string) {
this.httpServ.searchData(inputVal)
.then(res => {
// we are pushing values inside callback now, so we have correct values!
// and 'SimpleSearch' stands for the interface
this.Output.push(<SimpleSearch>{kw: inputVal, resp: res});
});
}
}
This should take care of it that the corresponding keyword will have the corresponding response! :)
PS. Worth noticing here, is that you'd maybe want to display the keyword while we are waiting for the response for that keyword, I ignored it here though and applied the same as you are currently using.

Resources