Adding key value pair to object inside forEach loop - foreach

I'm trying to add a thenable result to an object using a forEach loop. I can see the entries when I console.log the results, but when I try to use them for other parts of my code, I get an empty object.
I was getting an error previously telling me that the object's name (results) was not defined. I moved the object outside of the function and now I just get an empty object returned when I try to return the values of the object.
I tried this first:
let results = {};
// Check for all videos in cache (returns [])
const findAllVidsInCache = (videoArray) => {
videoArray.forEach(video => {
check(video).then(res => {
// resultsArray.push(res);
results[video] = res;
return results;
});
});
return results;
}
Then I tried this:
let results = {};
// Check for all videos in cache (returns [])
const findAllVidsInCache = (videoArray) => {
videoArray.forEach(video => {
check(video).then(res => {
// resultsArray.push(res);
results[video] = res;
return results;
});
});
let values = Object.values(results);
return values;
}
But I still keep getting an empty object when the function is called (I'm using devTools to call the function so nothing else should be interfering with it).
What I'm looking for, and what I can see in the console when I log it to the console, is an object that appears like so:
'video1': false,
'video2': false,
'video3': false,
'video4': true,
'video5': false,
...
Up to 12 videos.
Any ideas what I'm doing wrong here?

Try reading about promise handling. return results; returns a promise.

Related

Mapping a Stream<List> to another type is returning a Stream<Null>

I'm trying to transform a Stream of a list of one type into a Stream of a list of another type, and having an issue with this.
I have this list of Habits that I'm streaming from Firebase, and I want to accept that stream in a function, and return a new stream that is a list of ViewModels of another type from it. But my function is returning a stream of the wrong type.
Here is my code:
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.map((habitsList) {
habitsList.map(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) => completion.date
.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}
I am getting a compile error because the result variable is showing as type Stream<Null> when I hover over it, where I would expect it to be Stream<List<HabitCompletionViewModel>>. Any idea what I'm doing wrong?
Your outer .map call does not have a return statement which is why you are getting a Stream<Null>.
So add a return statement like so:
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.map((habitsList) {
// added return statement here
return habitsList.map(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) =>
completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}
However the above code still has an error because it is now returning a Stream<List<Future<HabitCompletionViewModel>>> instead of the desired Stream<List<HabitCompletionViewModel>>. To solve this you can use .asyncMap instead of .map.
Stream<List<HabitCompletionViewModel>> _getTodaysHabits(
Stream<List<Habit>> habitsStream) {
var result = habitsStream.asyncMap((habitsList) {
return Stream.fromIterable(habitsList).asyncMap(
(habit) async {
await _getHabitCompletionsCurrent(habit);
HabitCompletion completion = habit.completions!.firstWhere(
(completion) =>
completion.date.dayEqualityCheck(DateTime.now().startOfDate()));
return HabitCompletionViewModel(completion: completion, habit: habit);
},
).toList();
});
return result;
}

Dart streams error with .listen().onError().onDone()

I have an issue with some code that looks like this. In this form I have an error
The expression here has a type of 'void', and therefore can't be used.
Try checking to see if you're using the correct API; there might be a function or call that returns void you didn't expect. Also check type parameters and variables which might also be void.dart(use_of_void_result).
If I remove the .onDone() the error goes away. Why? ELI5 please :-)
I was looking at https://api.dart.dev/stable/2.7.0/dart-async/Stream/listen.html but seem to still be misundertanding something.
I also read https://api.dart.dev/stable/2.7.0/dart-async/StreamSubscription/onDone.html
serviceName.UploadThing(uploadRequest).listen((response) {
uploadMessageOutput = response.message;
if (response.uploadResult) {
showSuccess();
} else {
showError();
}
getUploadFileList(event);
isSaveInProgress = false;
}).onError((error) {
isSaveInProgress = false;
_handleFileUploadError(uploadRequest, error);
}).onDone(() {
isSaveInProgress = false;
});
Your code is almost right, but will only require a simple change to work correctly.
You would be seeing the same error if you swapped the ordering of onError and onDone, so the issue has nothing to do with your stream usage. However, you're attempting to chain together calls to onError and then onDone which won't work since both of these methods return void.
What you're looking for is cascade notation (..), which will allow for you to chain calls to the StreamSubscription returned by listen(). This is what your code should look like:
serviceName.UploadThing(uploadRequest).listen((response) {
uploadMessageOutput = response.message;
if (response.uploadResult) {
showSuccess();
} else {
showError();
}
getUploadFileList(event);
isSaveInProgress = false;
})..onError((error) { // Cascade
isSaveInProgress = false;
_handleFileUploadError(uploadRequest, error);
})..onDone(() { // Cascade
isSaveInProgress = false;
});

Cannot read property 'length' of null when using MatPaginator

I keep on getting this error:
core.js:1542 ERROR TypeError: Cannot read property 'length' of null
at MatTableDataSource.push../node_modules/#angular/material/esm5/table.es5.js.MatTableDataSource._filterData (table.es5.js:702)
at MapSubscriber.project (table.es5.js:657)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at CombineLatestSubscriber.push../node_modules/rxjs/_esm5/internal/observable/combineLatest.js.CombineLatestSubscriber.notifyNext (combineLatest.js:83)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/InnerSubscriber.js.InnerSubscriber._next (InnerSubscriber.js:15)
at InnerSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at BehaviorSubject.push../node_modules/rxjs/_esm5/internal/BehaviorSubject.js.BehaviorSubject._subscribe (BehaviorSubject.js:22)
at BehaviorSubject.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:42)
at BehaviorSubject.push../node_modules/rxjs/_esm5/internal/Subject.js.Subject._trySubscribe (Subject.js:89)
I get my data from a service that gets from a database. It functions just fine. What I mean is the functionality is right. I can do the paging it's just that I get this error in the inspector. Please see my code below:
ngOnInit() {
if (this.genParams.buildingId === null || this.genParams.buildingId === undefined) {
this.router.navigate(['/main/viewproperties']);
}
this.buildingId = this.genParams.buildingId;
this.getUnits();
}
public getUnits() {
this.isLoading = true;
this.unitService.newGetUnits(this.buildingId)
.subscribe((data: any) => {
this.ELEMENT_DATA = data;
this.dataSource = new MatTableDataSource(this.ELEMENT_DATA);
this.dataSource.paginator = this.paginator;
this.isLoading = false;
console.log(this.ELEMENT_DATA);
}, err => {
console.log(err);
});
}
This is in my html:
<mat-paginator [pageSizeOptions]="[1, 5, 10, 20]" showFirstLastButtons></mat-paginator>
I would really appreciate your help.
I suspect that this is a scope issue. Try adding this to the class, not a function. You refer to this.datasource but setting it up as new in the function so I assume you just declare the var in the class. I've seen this error many times and it is when my dataSource is not receiving data but you seem to indicate that your table is functioning with data.
Stackblitz example
// For data table operations.
private dataSource = new MatTableDataSource();
private dataLength: number;

q promise and map doesn't change after iteration

I'm using Q Promises to retrieve data from my redis repository. The problem I'm having, is that through each iteration, the array object (localEncounter) I'm using to store data returned from the chained functions is never updated at each iteration. Previously, I tried to solve this with a foreach loop and spread but the results were the same.
How should I correct this so that localEncounter is updated at each iteration, and ultimately localEncounters contains correct data when returned? Thank you.
var localEncounters = [];
var localEncounter = {};
Promise.all(ids.map(function(id) {
return localEncounter, getEncounter(id, client)
.then(function (encounter) {
encounterObject = encounter;
//set the fields for the return object
localEncounter['encounterid'] = encounterObject[f_id];
localEncounter['screeningid'] = encounterObject[f_screening_id];
localEncounter['assessmentid'] = encounterObject[f_clinical_assessment_id];
localEncounter['psychevalid'] = encounterObject[f_psych_eval_id];
//get screening
return getScreening(encounterObject[f_screening_id], client);
})
.then(function (screening) {
//set the fields for the return object
localEncounter['screeningbegintime'] = screening[f_begin_time];
//get assessment
return getAssessment(localEncounter['assessmentid'], client);
})
.then(function (assessment) {
//set the fields for the return object
localEncounter['assessmentbegintime'] = assessment[f_begin_time];
//get psycheval
//localEncounters.push(assessment);
return getPsychEval(localEncounter['psychevalid'], client);
})
.then(function (psychEval) {
//set the fields for the return object
localEncounter['assessmentbegintime'] = psychEval[f_begin_time];
localEncounters.push(localEncounter);
}
, function (reason) {
console.log(reason); // display reason why the call failed;
reject(reason, 'Something went wrong creating the encounter!');
})
})).then(function(results) {
// results is an array of names
console.log('done ');
resolve(localEncounters);
})
Solution: I only needed to move the declaration of localEncounter inside the map iterator
before:
var localEncounter = {};
Promise.all(ids.map(function(id) {
after:
Promise.all(ids.map(function(id) {
var localEncounter = {};
This now allows that each id iteration gets its own localEncounter object.

How can I access the result of the response of HttpRequest in Dart?

After many attempts to get the content of the response in HttpRequest, I failed completely to know or understand why I can't have what I want, and I must mention that I can log and manipulate the response only inside an onReadyStateChange (onLoad and onLoadEnd are giving me the same results!), but I really want that value outside the callback.
Here is the part of code that I'm stuck with
Map responsData;
req=new HttpRequest()
..open(method,url)
..send(infojson);
req.onReadyStateChange.listen((ProgressEvent e){
if (req.readyState == HttpRequest.DONE ){
if(req.status == 200){
responsData = {'data': req.responseText};
print("data receaved: ${ req.responseText}");
//will log {"data":mydata}
}
if(req.status == 0){
responsData = {'data':'No server'};
print(responsData );
//will log {"data":No server}
}
}
});
//anything here to get responsData won't work
You have to assign an onLoad callback before you call send.
I'm not sure what you mean with only inside an onReadyStateChange.
Maybe you want to assign the responseText to a variable outside the the callback.
Create a method:
Future<String> send(String method, String url, String infojson) {
var completer = new Completer<String>();
// var result;
req=new HttpRequest()
..open(method,url)
..onLoad.listen((event) {
//print('Request complete ${event.target.reponseText}'))
// result = event.target.responseText;
completer.complete(event.target.responseText);
})
..send(infojson);
return completer.future;
}
and call this method like
var result;
send(method, url).then(
(e) {
// result = e;
print('Request complete ${e}'));
});

Resources