react-native. Reference Error value is not defined - react-native

I'm having a problem setting a state in react-native. I can console.log the value just fine but when I call setState() I get Reference error 'targetSpreadsheet' is not defined.
This is in following function
getCategories = (file) => {
console.log(this.state.targetSpreadsheet); // works fine
this.setState({targetSpreadsheet: file}); // targetSpreadsheet is not defined.
}
And a picker that calls it
<SimplePicker
ref={'picker2'}
options={this.state.spreadsheetNames}
onSubmit={(option) => {
for(var i = 0; i < this.state.spreadsheets.files.length; i++){
if(this.state.spreadsheets.files[i].name === option){
let file = this.state.spreadsheets.files[i];
this.getCategories(file);
break;
}
}
}}
/>
EDIT
constructor
constructor(props){
super(props);
this.state = {
targetSpreadsheet: ''
}
this.getCategories = this.getCategories.bind(this);
}

This show you want to access the spreadsheets object that has files array in it
this.state.spreadsheets.files[I]
But In your constructor you have initialised targetSpreadsheet as and string object, so you are getting error.
this.state = {
targetSpreadsheet: ''
}
Solution : You need to make it as an object with files as an empty array.
this.state = {
targetSpreadsheet: {
files:[]
}
}

Related

When i trying for a form validate im getting this error (Property 'email' does not exist on type 'Readonly<{}>')

interface IRegisterProps {
navigation: any;
}
interface IRegisterState { }
class RegisterScreen extends React.PureComponent<IRegisterProps, IRegisterState> {
constructor(props: any) {
super(props);
this.state = {
nick: "",
nickError: ""
};
}
nickValidator(){
if(this.state.mail=""){
}
}
when im trying to do validate im geeting this error: Property 'email' does not exist on type 'Readonly<{}>'
if(this.state.mail=""){ this is my error line
While comparing, you can't assign a value to variable,
use == instead
if(this.state.mail==""){
Also please cross check if it's mail or email in your state and change the condition accordingly
Secondly, add property email to your state
this.state = {
...
email: ''
};
or make it type of any
this.state: any = {
...
};
If you using interface in the state that define the property in the interface too
interface IRegisterState {
email: string
}

How to render text only after a Promise has been resolved in React Native?

I am trying to dynamically translate some text to be displayed when a user clicks on the translate button, but I can't get it to save my values outside of the Promise. I haven't worked much with Promises and every example only shows console.log, rather than saving values outside of the Promise. I don't really understand how they work. Here is (most of) the code I am trying to fix:
constructor(props) {
super(props);
this.state = {
dynamicTranslate: this.props.dynamicTranslate,
};
}
// I've tried this method as both sync and async (with await) but neither work
googleTranslate = (key) => {
const translator = TranslatorFactory.createTranslator();
// translate returns a Promise
return translator.translate(key, i18n.locale)
.then((response) => {return response});
}
renderText() {
// getting some values....
// this loops through all the feedback information
for (var i = 0; i < components_feedback.length; i++) {
let label = (some string);
let value = (some string);
// to do: call google translate call here if Boolean(this.state.dynamicTranslate)
if (Boolean(this.state.dynamicTranslate)) {
// I am ultimately trying to save the translation string from googleTranslate()
// in label/value so I can push it into feedbacks
label = this.googleTranslate(label);
value = this.googleTranslate(value);
}
feedbacks.push({label: label, value: value, type: comp.type})
}
return (
// some stuff
feedbacks.map((feedback, index)) => {
// some stuff
<Text>{feedback.label}</Text>
<Text>{feedback.value}</Text>
// some other stuff
});
);
}
render() {
return (
<View>{this.renderText()}</View>
);
}
One of the issues I'm running into is that label/value is a Promise if translation is on. If I try to make renderText() an async method, it is also turned into a Promise which render() can't handle. No idea where to go from here.
Solved this issue. Solution is to put the loop in an async function that (ideally) gets called on construction. This loop was edited to await the returns and push to local arrays of labels and values then saves those in state. You can compare the length of those arrays to the expected length (compare length of last array being used to be positive that it has finished) and that is how you can know if the Promises have returned. Paraphrased code:
constructor(props) {
this.state = {
translatedLabels = []
translatedValues = []
}
this.asyncFunction()
}
asyncFunction = () => {
labels = []
for loop
label = await promise
labels.push(label)
//same for values
end for
this.setState({translatedLabels: labels})
}
//later
renderText() {
if (this.state.translatedLabels.length === whatever) {
// do your stuff as you know the async function has finished
}
}
render() {
return (
{this.renderText()}
);
}

Angular 7 application, I want to do an if() condition that checks the Input() value passed from parent

I am passing data from parent to child. In the HTML, i can see the value of the Input() variable. However, on my TS file, when I try to do a conditional to check the value of Input() it is always an empty string. Here is my code for the child:
#Input() checkDbStatus = '';
ngOnInit() {
this.initForm();
this.dbStatusCheck();
}
// disables all controls in a form group
disableControl(group: FormGroup){
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.get(key);
abstractControl.disable();
})
}
// disable form controls if dbStatus !== update
dbStatusCheck() {
if(this.checkDbStatus !== 'update') {
this.disableControl(this.demographicsSectionOne);
this.disableControl(this.demographicsSectionTwo);
this.disableControl(this.demographicsSectionThree);
this.disableControl(this.demographicsSectionFour);
this.disableControl(this.demographicsSectionFive);
}
}
I think you need to use the ngChange lifecycle.
https://angular.io/api/core/OnChanges
export class YourComponent implements OnChanges
ngOnChanges(changes: SimpleChanges) {
if (changes.checkDbStatus.currentValue !== changes.checkDbStatus.previousValue) {
this.doStatusCheck();
}
}
Try set and get input() function
https://angular.io/guide/component-interaction
_checkDbStatus: any;
#Input() set checkDbStatus(data: any) {
this._checkDbStatus = data;
this.dbStatusCheck(data)
}
get checkDbStatus(){return this._checkDbStatus }

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: ''

I am writing a component which takes one #Input parameter and display it in the html bit I am getting below error.
SuggestionsComponent.html:54 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '<p>so string value</p>
'.
at viewDebugError (core.js:9801)
at expressionChangedAfterItHasBeenCheckedError (core.js:9779)
at checkBindingNoChanges (core.js:9948)
at checkNoChangesNodeInline (core.js:14002)
at checkNoChangesNode (core.js:13976)
at debugCheckNoChangesNode (core.js:14805)
at debugCheckDirectivesFn (core.js:14707)
at Object.eval [as updateDirectives] (SuggestionsComponent.html:54)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:14689)
at checkNoChangesView (core.js:13814)
Here is the component.
export class SuggestionsComponent implements OnInit, AfterViewInit {
#Input() suggestions: Array<Suggestions>;
#Output() approveSuggestion = new EventEmitter<Object>();
constructor(
private elementRef: ElementRef,
) {
}
ngOnInit() {
}
ngAfterViewInit() {
if (this.suggestions && this.suggestions.length > 0) {
this.suggestions
.map((value, index) => {
this.suggestions[index].newSuggestion = value.descriptionSuggestion;
});
}
}
The problem is changing component #Input variable value in ngAfterViewInit(). At that time angular changes view and making some change in bind value in upsets angular.
So moving the #input() value to ngOnInit solves the problem as its the method which executes during component bootstrap.
ngOnInit() {
// This is placed here in the in after view init is because it will throw exception as view will be change at that time
this.suggestions
.map((value, index) => {
this.suggestions[index].newSuggestion = value.descriptionSuggestion;
});
}
ngAfterViewInit() {
if (this.suggestions && this.suggestions.length > 0) {
this.suggestions
.map((value, index) => {
this.elementRef.nativeElement.querySelector('.class' + index).style.display = 'none';
});
}
}

multidimensional object state in constructor

Happy New Year...
I am extremely new to RN and am building a small app to get a feel for it.
I am trying to figure out if there is a way to clean this part up.
Below I have a nested multidimensional object state in the constructor and a reset function.
I have four input fields and a plain text area which I update dynamically based on a result.
Now whilst this works it feels not so clean, say if I wanted to add another nested multidimensional object state which sets different default values on reset I am going to have to add another if block to handle that so the it compounds the problem even further.
Any thoughts how to improve this or am I going about it the wrong way :/
constructor(props) {
super(props)
this.state = {
input1: '',
input2: '',
input3: '',
input4: '',
result: {
'ratio': 0,
'style': '',
},
}
}
reset() {
let newState = {};
for (const field of Object.keys(this.state)) {
if (field == 'result') {
this.setState({
result: {
ratio: 0,
style: '',
}
});
continue;
}
newState[field] = '';
}
this.setState(newState);
}
** edit **
To make it clearer if I add another multidimensional object to the state I will need to include another if statement
for (const field of Object.keys(this.state)) {
if (field == 'reset') {
// ...
}
if (field == 'extra') {
// ...
}
newState[field] = '';
}
Ideally what I need is a copy of this.state before its updated then just restore the copy which has the default parameters this.setState(copy)
Many thanks.
I am not entirely sure what you mean by 'nested', but here are a couple of suggestions:
reset() {
let newState = {};
for (const field of Object.keys(this.state)) {
if (field == 'result') {
newState.result = {
ratio: 0,
style: '',
};
}else{
newState[field] = '';
}
}
this.setState(newState);
}
Looping this way you avoid triggering multiple renders since you only call setState once.
Edit: If you want to avoid checking for fields with known names, you can just access those directly. 'Wrap' all your inputs in a new entry in the state, and just loop through that one:
constructor(props) {
super(props)
this.state = {
inputs:{
input1: '',
input2: '',
input3: '',
input4: '',
},
result: {
'ratio': 0,
'style': '',
},
extra = {
extraKey: 1,
}
}
}
reset() {
let newState = {};
newState.result = {ratio: 0, style: ''};
newState.extra = // ...
newState.inputs = {};
for (const field of Object.keys(this.state.inputs)) {
newState.inputs[field] = '';
}
this.setState(newState);
}
It is a bit cumbersome to use a loop to update the keys in an object, but I cannot think of a simpler solution when the key names are not known in advance.