ionic 4 capacitor storage get not working properly - ionic-framework

Recently I moved from Cordova to capacitor storage API. And I am having a very strange issue. At page1 I am setting 4 values to local storage, but when I access these values on another page, one value is getting displayed as null.
I tried many approaches but value user_id is always null.
I made sure value is getting stored in local storage.
I am also attaching images of console.log after setting and retrieving values from local storage
storage.service.ts
async set(key: string, value: any): Promise<any> {
if(value == null || value == undefined) {
console.log("dont'do")
}
else {
try {
await Storage.set({
key: key,
value: value
});
return true;
} catch (reason) {
console.log(reason);
return false;
}
}
}
// to get a key/value pair
async get(key: string): Promise<any> {
try {
const result = await Storage.get({ key: key });
console.log('storageGET: ' + key + ': ' + result.value);
if (result != null) {
return result.value;
}
else {
console.log("null from service")
return null;
}
} catch (reason) {
console.log(reason);
return null;
}
}
page1.ts
this.storageService.set('user_id',data[i].id ).then(val => console.log(val))
this.storageService.set('email', data[i].email).then(val => console.log(val))
this.storageService.set('phone_number', data[i].mobile_no).then(val => console.log(val))
this.storageService.set('firebase_uid', data[i].firebase_uid).then(val => console.log(val))
page2.ts
this.storageService.get('user_id').then(val => console.log(val))
this.storageService.get('email').then(val => console.log(val))
this.storageService.get('phone_number').then(val => console.log(val))
this.storageService.get('firebase_uid').then(val => console.log(val))
Console.log after setting values
console.log after retrieving local storage values

For everyone who needs it, unlike Cordova capacitor get API doesn't support numbers.
So you have to convert it into string while setting into the storage only using JSON.stringify(value)
example :
await Storage.set({
key: 'key',
value: JSON.stringify(value)
});

Related

How to pass a `where` clause to a function in Dart?

There is a function, getItems, and I would like to be able to have multiple where to modify the resulting list. I am new to Dart and cannot find the syntax for passing in a where.
I tried creating functions with custom where to call getItems, but cannot due to the async nature of getItems.
Future<List<IioMenuItem>> getItems() async {
// ...
final db = await openDatabase(path, readOnly: true);
final List<Map<String, dynamic>> maps = await db.query('menu_items');
final dbFilteredItems = maps.map((item) => IioMenuItem(
// assign values code removed
)).where((element) { // <-- make 'where' replaceable
if (filterState == FilterState.all) {
return true;
} else {
return element.type.name == filterState.name;
}
}).toList(growable: false);
return List.generate(dbFilteredItems.length, (i) {
return dbFilteredItems[i];
});
}
The failed attempt
Future<List<IioMenuItem>> menuItems(FilterState filterState) async {
final dbFilteredItems = getItems().where((element) { // The method 'where' isn't defined for the type 'Future'.
if (filterState == FilterState.all) {
return true;
} else {
return element.type.name == filterState.name;
}
}).toList(growable: false);
return List.generate(dbFilteredItems.length, (i) {
return dbFilteredItems[i];
});
}
Can I please get help?
The term you're looking for is a "closure" or "first class function".
See Functions as first-class objects on the Language guide.
"A where" isn't a thing. It's not a noun. Iterable.where is just the name of a function, and that function happens to take a function as a parameter, and uses it to determine what things to keep.
In this specific case, you want a function that takes a IioMenuItem, and returns a boolean that determins where or not to keep it. The type of that is a bool Function(IioMenuItem) (see Function).
I called it "predicate":
Future<List<IioMenuItem>> menuItems(
FilterState filterState,
bool Function(IioMenuItem) predicate // <- Take it in as a parameter
) async {
return (await getItems())
.where(predicate) // <- pass it along as an argument to `where`
.toList(growable: false);
}
You can pass any test inside a where.
filterItems(Map<String,dynamic> element) {
if (filterState == FilterState.all) {
return true;
} else {
return element.type.name == filterState.name;
}
}
final dbFilteredItems = maps.map((item) => IioMenuItem(
// assign values code removed
)).where(filterItems).toList(growable: false);
Use then in future
getItems().then((value) => value.where((element ...
Use await to call async functions.
Future<List<IioMenuItem>> menuItems(FilterState filterState) async {
final dbFilteredItems = (await getItems()).where((element) { // await has to be used here.
if (filterState == FilterState.all) {
return true;
} else {
return element.type.name == filterState.name;
}
}).toList(growable: false);
return dbFilteredItems;
}

Flutter The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type?

I am returning a data from an API using flutter and I have a problem telling me that
The body might complete normally, causing 'null' to be returned, but the
return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
This is my method:
Future<void> getDoctorsFromApi() async {
List<int> ids = await findAllDoctor().then((list) {
return list.map((e) => e.syncedId).toList();
});
doctors = await DoctorApi.getDoctors(ids).then((response) { // this is the line where error occurs
if (response.statusCode == 200) {
Iterable list = json.decode(response.body);
return list.map((model) => Doctor.fromJson(model)).toList();
} else {
_showMyDialog();
}
});
setState(() {
insertDoctors(database!);
});
}
What will be the value of doctors if response.statusCode is not 200? Handle that
by creating a nullable local variable:
final List<Doctor>? result = await DoctorApi.getDoctors(ids).then((response) {
if (response.statusCode == 200) {
Iterable list = json.decode(response.body);
return list.map((model) => Doctor.fromJson(model)).toList();
}
return null;
});
if (result == null) {
_showMyDialog();
} else {
doctors = result;
setState(() => insertDoctors(database!));
}
Just add some return or throw statement at the end of your function.
setState(() {
insertDoctors(database!);
});
throw ''; # or return something
}

Future returns list before being populated

I have the following method:
Future<List<Job>> getUserJobs() async {
Query query = _firebaseDatabase
.reference()
.child("jobs")
.child(_firebaseAuth.currentUser.uid)
.orderByKey();
List<Job> userJobs = [];
if (query == null) {
return userJobs;
}
query.onValue.listen((event) {
Map<dynamic, dynamic> values = event.snapshot.value;
values.forEach((key, value) {
userJobs.add(Job.fromJson(key, Map.from(value)));
});
});
return userJobs;
}
I want to get this response in another class, however, the list returned by the above method is always []. I checked and the userJobs list is indeed populated but the return statement is executed before.
The structure of the database is:
Job collection has user IDs and for each user ID I have several job keys (each with its job data).
Try this:
Future<List<Job>> getUserJobs() async {
List<Job> userJobs = [];
// Query query =
await _firebaseDatabase
.reference()
.child("jobs")
.child(_firebaseAuth.currentUser.uid)
.once()
.orderByKey().then((result) async {
if (result.value != null) {
result.value.forEach((key, childSnapshot) {
userJobs.add(Job.fromJson(key, Map.from(childSnapshot)));
});
} else {
print(
'getUserJobs() no jobs found');
}
}).catchError((e) {
print(
'getUserJobs() error: $e');
});
// if (query == null) {
// return userJobs;
// }
// query.onValue.listen((event) {
// Map<dynamic, dynamic> values = event.snapshot.value;
// values.forEach((key, value) {
// userJobs.add(Job.fromJson(key, Map.from(value)));
// });
// });
return userJobs;
}
your loop also needs to be async..otherwise the method will return before the loop finishes, returning the empty List.. been there and got quite frustrated by this..
also always use .catchError callback.. it tells you what's going wrong ;)

rxDart BehaviorSubject's value is not null on sink.addError

I'm new to using rxDart & bloc. I implement a transform to validate input. When I listen to the data on the sink it outputed correctly (null if error & value if no error), but when I print the value of the BehaviorSubject it wont represent null on error and prints the value that should be an error. Here is my code:
final _phoneNumberController = BehaviorSubject<String>();
Function(String) get setPhoneNumber => _phoneNumberController.sink.add;
Observable<String> get phoneNumberValue =>
_phoneNumberController.stream.transform(_validatePhoneNumber);
final _validatePhoneNumber = StreamTransformer<String, String>.fromHandlers(
handleData: (phoneNumber, sink) {
if (phoneNumber.length > 5 && isNumeric(phoneNumber)) {
sink.add(phoneNumber);
} else {
sink.addError(StringConstant.phoneNumberValidationErrorMessage);
}
});
void signUserIn() {
print(_phoneNumberController.stream.value); // Prints value that should be an error
}
SignInBloc() {
phoneNumberValue.listen((data) => print(data)); // Just Fine
}
You're listening to data but you don't listen to sink errors. change your code to:
SignInBloc() {
phoneNumberValue.listen((data) {
print(data);
},
onError: (_){
print(_.toString());
});
}

Ionic 2 native Http plugin not returning response

I am using Ionic 2 HTTP native plugin and running http.post from a provider. The data is received from the API in the provider but does not seem to be being sent back to the page component. I get error:
TypeError: undefined is not an object (evaluating
'this.authProvider.login(formData).then')
PAGE: login.ts
doLogin() {
this.spinner = 'true';
this.authProvider.login(formData).then((result:any) => {
if(result.status == 'isTrue') {
this.storage.set('userId', result.userId);
this.storage.set('userToken', result.token);
this.storage.set('profilePic', result.profilepic);
this.storage.set('userUsername', result.username);
this.navCtrl.setRoot(TabsPage);
}
else {
this.presentToast('Incorrect email or password, try again');
console.log('not a user');
}
this.spinner = 'false';
}, (err) => {
});
}
PROVIDER: authProvider
login(data) {
if (this.platform.is('ios'))
{
this.http2.post(this.apiUrl+'/api/login', data, {})
.then((dataresult) => {
return dataresult; // this outputs ok in console.log, but doesnt
return back to page
//console.log(dataresult);
})
.catch(error => {
});
}
}
You should have to return promise from authProvider,
return new Promise(resolve => {
this.http2.post(this.apiUrl+'/api/login', data, {})
.subscribe(dataresult => {
resolve(dataresult);
});
});