I'm trying to filter this .json in order not to show private videos.
It's for a app of a youtube channel.
There are some videos that are private and I don't want to show them in the app.
I need help filtering the .json
Currently it's returning an empty json. if I remove the .map it returns the complete list of videos with the privete ones.
getPlayListVideos(listId: string) {
return this.http.get('https://www.googleapis.com/youtube/v3/playlistItems?key=' + this.apiKey + '&fields=items/snippet/resourceId/videoId,items/snippet/publishedAt,items/snippet/title,items/snippet/thumbnails/high/url&playlistId=' + listId +'&part=snippet,id&maxResults=25')
.map((res) => {
return res.json()['items'].filter(item => {
if(item.snippet.title === 'Private video'){
return false;
}
});
})
}
You need to return true if you don't want to filter the current item. Currently you're returning either false or undefined implicitly since you don't return anything in that case. So you need to do this:
if(item.snippet.title === 'Private video'){
return false;
} else {
return true;
}
or better yet return item.snippet.title !== 'Private video'.
Bonus formatting - I'd write the whole thing like this personally:
getPlayListVideos(listId: string): any[] {
return this.http.get('https://www.googleapis.com/youtube/v3/playlistItems?key=' + this.apiKey + '&fields=items/snippet/resourceId/videoId,items/snippet/publishedAt,items/snippet/title,items/snippet/thumbnails/high/url&playlistId=' + listId + '&part=snippet,id&maxResults=25')
.map(res => res.json()['Items'])
.map((items: any[]) => items.filter(item => item.snippet.title !== 'Private video'))
}
Related
I use Sequelize to load items from database. The item contain a number type attribute called tValue, if tValue is null, then I need to assign a value to it, if not null, then do nothing and then pass all items to a function and it will return a new array.
What I want is to revert those updated items, make them back to null tValue before I save this list of array to database.
The issues is I don't know which item originally contain null tValue, because all of them have value now.
Can I give an object a temporary mark, so I can revert those items with mark.
The code snippet I do to assign value is like this
const mustHaveTValueArray = await Promise.all(
samples.map(async (s) => {
if (!s.tValue) {
console.warn(`sample ${s.id} do not have a t value`);
await s.update({ tValue: randomValue });
return s;
} else {
return s;
}
})
);
mustHaveTValueArray will be passed to a function, and return a new array
const newArray = reorderFunction(mustHaveTValueArray)
Each element in newArray now have valid tValue, how can I detect those originally have null tValue
the idea just come up in my head, guys
let temporaryIds = [];
const mustHaveTValueArray = await Promise.all(
samples.map(async (s) => {
if (!s.tValue) {
console.warn(`sample ${s.id} do not have a t value`);
await s.update({ tValue: randomValue });
temporaryIds.push(s.id);
return s;
} else {
return s;
}
})
);
Then I can use this temporaryIds to find which one originally have null tValue, like this
const finalArray = await Promise.all(
newArray.map(async (n) => {
if (temporaryIds.includes(n.id)) {
console.log('revert');
await n.update({ tValue: null });
return n;
} else {
return n;
}
})
);
what do you think, is it this make sense to you, guys
22/10/22 update:
model.update actually is calling set and then calling save, so what I need to do, I should use set instead of update, otherwise it will write db which is not my purpose. setis perfectly fit my situation, instruction from official document:
Set is used to update values on the instance (the sequelize
representation of the instance that is, remember that nothing will be
persisted before you actually call save). In its most basic form set
will update a value stored in the underlying dataValues object.
so updated code would be
const mustHaveTValueArray =
samples.map((s) => {
if (!s.tValue) {
console.warn(`sample ${s.id} do not have a t value`);
s.set({ tValue: randomValue });
return s;
} else {
return s;
}
});
And I can do whatever I want with mustHaveTValueArray
question solved
I am trying to check my all 4 images is uploaded to server without any error, then redirect to another page so i am trying to perform some sync checking in my code (I have total 4 images in my imgResultAfterCompress array). below is my code:
if(Boolean(this.updateImage(data.AddId))===true)
{
this.router.navigate(['/job-in-hotels-india-abroad']);
}
updateImage(AddId:number):Observable<boolean>
{
this.cnt=0;
this.uploadingMsg='Uploading Images...';
this.imgResultAfterCompress.forEach( (value, key) => {
if(value!=='')
{
this.itemService.updateImage(this.employer.ID,AddId,key,value).subscribe(data=>{
if(data && data.status == 'success') {
this.uploadingMsg=this.uploadingMsg+'<br>Image No - '+(key+1)+' Uploaded.';
this.cnt++;
}
else
this.alertService.error(data.message);
});
}
if(this.cnt==4)
this.uploadingDone= true;
else
this.uploadingDone= false
});
return this.uploadingDone;
}
Every time i am getting cnt value is 0, i want its value = 4 (completely uploaded all images) then redirection will occurred.
The easier way is to wrap your observables into a single one, using zip operator
https://rxjs-dev.firebaseapp.com/api/index/function/zip
Thus once every request is finished successfully your zipped Observable will be fulfilled.
UPDATE:
This is how I think it should look like. I could miss something specific, but the global idea should be clear
redirect() {
this.updateImages(data.AddId).subscribe(
() => this.router.navigate(['/job-in-hotels-india-abroad']),
error => this.alertService.error(error.message)
)
}
updateImages(AddId: number): Observable<boolean[]> {
this.uploadingMsg = 'Uploading Images...';
const requests: Observable<boolean>[] = [];
this.imgResultAfterCompress.forEach((value, key) => {
if (!value) {
return;
}
requests.push(
this.itemService.updateImage(this.employer.ID, AddId, key, value)
.pipe(
tap(() => this.uploadingMsg = this.uploadingMsg + '<br>Image No - ' + (key + 1) + ' Uploaded.'),
switchMap((data) => {
if (data && data.status == 'success') {
return of(true)
} else {
throwError(new Error('Failed to upload image'));
}
})
)
)
});
return zip(...requests);
}
Finally got the desire result by using forkJoin
Service.ts:
public requestDataFromMultipleSources(EmpId: number,AddId:number,myFiles:any): Observable<any[]> {
let response: any[] = [];
myFile.forEach(( value, key ) => {
response.push(this.http.post<any>(this.baseUrl + 'furniture.php', {EmpId: EmpId, AddId:AddId,ImgIndex:key,option: 'updateAdImg', myFile:value}));
});
// Observable.forkJoin (RxJS 5) changes to just forkJoin() in RxJS 6
return forkJoin(response);
}
my.component.ts
let resCnt=0;
this.itemService.requestDataFromMultipleSources(this.employer.ID,AddId,this.imgResultAfterCompress).subscribe(responseList => {
responseList.forEach( value => {
if(value.status=='success')
{
resCnt++;
this.uploadingMsg=this.uploadingMsg+'<br>Image No - '+(value.ImgIndex+1)+' Uploaded.';
}
else
this.uploadingMsg=this.uploadingMsg+'<br>Problem In Uploading Image No - '+(value.ImgIndex+1)+', Please choose another one.';
});
if(resCnt === this.imgResultAfterCompress.length)
{
this.alertService.success('Add Posted Successfully');
this.router.navigate(['/job-in-hotels-india-abroad']);
}
else
this.alertService.error('Problem In Uploading Your Images');
});
You shouldn't try to make sync call within a loop. It is possible using async/await, but it's bad for app performance, and it is a common anti-pattern.
Look into Promise.all(). You could wrap each call into promise and redirect when all promises are resolved.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
I have a service with a delete function. The delete function will call an api and it will return true or false. When true, I will lookup the index in my array, splice it and return the new array. So for example
private items = [];
onItemDeleted = new Subject<any>();
delete(id:number): Observable<any> {
return this.http.delete('http://my.api.com/item/' + id)
.pipe(
switchMap(checkServerSuccessResponse),
map(data => {
const index1 = this.items.findIndex((element) => {
return element.id === id;
});
if (index1 >= 0 ) {
this.items.splice(index1,1);
}
this.onItemDeleted.next(this.items);
return this.items;
}
),
catchError(returnFalse),
);
}
I have a helper for the switchmap :
export function checkServerSuccessResponse(data: Response): Observable<any> {
return (data && data['success'] === true) ? of(data) : throwError("server responded false");
}
Although this works, I have a feeling the map section can reformatted. I first thought of filter (after the switchmap) to exclude the element with the id I've supplied, then emit the new array, but then I realised, the filter is not subscribed to the this.items array.
What would be the best approach to do this?
I don't know you other code, for example where this.items coming from, why do you publish updated items to onItemDeleted. But I would probably: a) pass this.items to delete method also like delete(id, items) because on the time when response will arrive, you don't know what will happen with this.items; b) that thing within the map, move to separate function, that will be removeById(items, id); c) simplify pipe. Like this:
private items = [];
onItemDeleted = new Subject<any>();
removeById(fromItems, id) {
const index1 = fromItems.findIndex((element) => {
return element.id === id;
});
if (index1 >= 0 ) {
fromItems.splice(index1,1);
}
return fromItems;
}
// who ever calls this, should provide copy of items also
// then you will be kinda protected from concurrent
// modification, when http response complete, but this.items
// is completely different, from when http request started
delete(fromItems, id:number): Observable<any> {
return this.http.delete('http://my.api.com/item/' + id)
.pipe(
switchMap(checkServerSuccessResponse),
map(data => this.removeById(fromItems, id)),
tap(items => this.onItemDeleted.next(items)),
catchError(returnFalse),
);
}
So basically, I have a web application that retrieves data from Firebase using rxjs observables.
here's my code,
initializeItems(){
this.travelList$ = this.plsdala.getTravelList()
.snapshotChanges()
.map(
changes => {
return changes.map(c=>({
key: c.payload.key, ...c.payload.val()
})).slice().reverse();//to reverse order
})
this.travelList$.subscribe(res => {
for(let i=0;i<res.length;i++){
this.ListOfitems.push (res[i].toAddress);
}
})
}
this is called from the constructor. problem here is that i cannot check if it is push successfully and if try to print in console , it wont print. why?
the element pushed is needed for filtering. heres is the code for filtter. but when i print the this.ListOfitems in console it is undefined and im wondering unto why? when the elements are initialized first
getItems(ev: any) {
console.log("awdaw");
console.log(this.ListOfitems);
if (this.ListOfitems.length>1){
console.log("otin");
let val = ev.target.value;
if (val && val.trim() != '') {
this.ListOfitems = this.ListOfitems.filter((ListOfitems) => {
return (ListOfitems.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
}
when you are declaring list of items if you want to push into the array you need to declare it empty first like this:
ListOfitems: string[] = [];
I'm think fundamentally i'm doing something wrong. I'm trying to find a single entity by pulling it from filtered list, if there isn't an entity there I need to create one.
I feel like this function is wrong because I should be returning an observable but instead returning nothing
getOrCreateNew(receiverId: number) : Observable<Conversation> {
var userId = this.identity.userInfo.id;
//TODO: you should be using an expression here, and having a builder for generating your
//filters in case you want to switch them in the future
var employerFilter = new PropertyFilterNode("EmployerUserId", FilterCondition.Equal, receiverId.toString());
var employeeFilter = new PropertyFilterNode("EmployeeUserId", FilterCondition.Equal, userId.toString());
let conversationFilter = new BinaryFilterNode(employerFilter, employeeFilter, Combiner.Or);
this.getList(conversationFilter).subscribe(entities => {
if (entities == null || entities.length == 0) {
let conversation: Conversation;
conversation.employerUserId = receiverId;
conversation.employeeUserId = userId;
return this.create(conversation);
}
else {
let entity = entities[0];
return Observable.of(entity); //.Return(entity)
}
});
return null;
}
How can I return an observable which is return from inside subscribe?
The way getList subscription works suggests that it is supposed to be mergeMap or switchMap (considering that create returns an observable as well):
return this.getList(conversationFilter).mergeMap(entities => {
if (entities == null || entities.length == 0) {
let conversation: Conversation;
conversation.employerUserId = receiverId;
conversation.employeeUserId = userId;
return this.create(conversation);
}
else {
let entity = entities[0];
return Observable.of(entity); //.Return(entity)
}
});
In this case an observable that is returned from getOrCreateNew should be subscribed in order to emit values because it isn't subscribed internally.
Place the return before this.getList also :
return this.getList(conversationFilter).subscribe(entities => {