I am new to rjxs programming so wondering how can I do the following.
const downloadUrls$: any = filelist.map((file: any) => {
const fileName = ...
const path = ...
const fileRef = ....
const task: any = ...
// get notified when the download URL is available
return task.snapshotChanges().pipe(
filter(snap => snap.state === TaskState.SUCCESS),
switchMap(() => from(fileRef.getDownloadURL()))
);
});
So in the above code instead of doing from(fileRef.getDownloadURL()) is there is a way I can do create a object like below and the return will be a list of below objects.
from (
{
name: fileName,
filepath: fileRef.getDownloadURL(),
relativePath: path
}
)
Method signature
`.getDownloadURL(): Observable<any>`
I don't have anything that is runnable from the code you provided, so I'm writing this just as a concept.
What you have is something that is already an Observable (fileRef.getDownloadURL()). And what we need is the new object. We can get there by mapping over the Observable from earlier, and changing it to the result that we need. Something along the lines of:
task.snapshotChanges().pipe(
filter(snap => snap.state === TaskState.SUCCESS),
switchMap(() => {
return fileRef.getDownloadURL().pipe(
map(url => ({
name: fileName,
filepath: url,
relativePath: path
}))
);
})
);
Related
In my service worker, I'm making use of workbox's precacheAndRoute from workbox-precaching. I want to cache files paths that already exist on IndexedDB since it varies across users. My code looks like this:
import { precacheAndRoute } from 'workbox-precaching';
import localforage from "localforage";
let formID;
const cachedFilesStore = localforage.createInstance({
name: 'page-id',
storeName: 'store'
})
const produceValuesFromCache = () => {
return cachedFilesStore.getItem('1')
.then(async (value) => {
formID = formID || value.form_id;
const cachedFiles = await cachedFilesStore.getItem(`${formID}`)
return [
...cachedFiles.manifest,
`/form/${formID}`
]
});
}
precacheAndRoute([], {
urlManipulation: async ({ url }) => {
const files = await produceValuesFromCache();
return files
}
})
It doesn't work as expected, instead I see an error like so: Uncaught TypeError: additionalURLs is not iterable. What am I doing wrong?
The code that dumps the files in IndexedDB is in the index.html file which is located at route form/${formID.
I am trying to set up react-table but am running into the issue of not being able to call hooks inside regular functions, specifically the useTable hook. Say I have something like this:
const Search = () => {
const [tableRows, changeTableRows] = useState([])
const columns = [
{ Header: 'One', accessor: 'header1'},
{ Header: 'Two', accessor: 'header2'}
]
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns, tableRows })
const apiSearch = (field, query) => {
axios.get(`ip/querypath?query=${query}&field=${field}`)
.then(({data}) => {
changeTableRows(data)
})
.catch(err => console.log(err))
return (
/* Render forms to input data and call apiSearch, and render actual table */
)
}
The line with useTable is only being called once, with no initial row data. I need it to update when I make the API call but I can't put a hook inside my apiSearch function. Even if I could, I don't know the right way to do it. This throws a syntax error:
let getTableProps, getTableBodyProps, headerGroups, rows, prepareRow
const apiSearch = (field, query) => {
...
{ getTableProps, getTablyBodyProps, headerGroups, rows, prepareRow } = useTable({ columns, tableRows })
}
I know I'm missing something basic and would appreciate any help.
So I have an api that is using fromFetch like so:
const myApi = () => {
const data$ = fromFetch(url);
return data$;
}
And my epic looks like so:
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mergeMap(action =>
myApi().pipe(
map(result => {
console.log(result)
return mapTo({ type: Actions.ADD_ITEMS, payload: result });
}),
),
),
);
};
The console.log(result) seems to work without a hitch and no problem. However I am getting the error:
Error: Actions must be plain objects. Use custom middleware for async actions.
As a side note I tried to do some basic testing and did this below and it worked fine so why is the epic above not working?
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mapTo({ type: Actions.ADD_ITEMS, payload: ['hello'] })
);
};
Made a codesandbox of the above with same error:
https://codesandbox.io/s/agitated-visvesvaraya-b8oun
Inside your map block you should just return the action directly. Your code wraps it with mapTo which is an operator that should only be used inside a pipe method.
So your fetchEpic should be:
export const fetchEpic = (action$: any) => {
return action$.pipe(
ofType(Actions.FETCH),
mergeMap(action =>
myApi().pipe(
map(result => {
console.log(result)
return{ type: Actions.ADD_ITEMS, payload: result };
}),
),
),
);
};
Here is the updated code sandbox: https://codesandbox.io/s/gracious-darkness-9dc9q
Since you're already using TypeScript, I found that many of such errors can actually found by the TypeScript compiler, if you type your epics correctly, e.g.
export const fetchEpic : Epic<YourActionType, YourActionType, YourStateType> = (action$) => { ..
first func:
updateMark(item: MarkDTO) {
this.service
.put(item, this.resource)
.subscribe(() => this.markEdit = null);
}
second func:
put(item: MarkDTO, rcc: string): Observable<MarkDTO> {
const rdto = new MarkRDTO(item);
const url = `${this.getUrl('base')}${rcc}/marks/${rdto.rid}`;
const obs = this.http.put<MarkDTO>(url, rdto, { withCredentials: true })
.pipe(map((r: MarkDTO) => new MarkDTO(r)))
.share();
obs.subscribe(newMark => this.storage.update(newMark, rcc));
return obs;
}
in service i need to update data after request
but also in same time i need to clear current editItem
all of it must be done after i subscribe to one httpRequest
.share() - suport from rxjs-compat package (i want to remove this dep in closest time)
without .share() - work only 1 of 2 steps
current rxjs version is 6.3.3
Help who can...
There is a pipeable share operator, that you would use the same way you use map() (i.e. inside pipe()) and thus doesn't need rxjs-compat.
But you don't need share() here. All you need is the tap() operator:
put(item: MarkDTO, rcc: string): Observable<MarkDTO> {
const rdto = new MarkRDTO(item);
const url = `${this.getUrl('base')}${rcc}/marks/${rdto.rid}`;
return this.http.put<MarkDTO>(url, rdto, { withCredentials: true })
.pipe(
map(r => new MarkDTO(r)),
tap(newMark => this.storage.update(newMark, rcc))
);
}
I need some help please.
I don't understand why this test does not work.
I use a #pipe.
import { inject } from '#angular/core/testing';
import { TreeHelperPipe } from 'app/shared/components/material-tree/tree-helper.pipe';
describe('Tree helper', () => {
let pipe: TreeHelperPipe;
beforeEach(() => {
pipe = new TreeHelperPipe();
});
describe('truncateString', () => {
it(
`should have string truncate and replace some part by dots`,
inject([TreeHelperPipe], (_TreeHelperPipe: any) => {
const item =
'http://namespace-example.fr/service/technique/version/ged-sharepoint/1.1';
const expectedItem =
'http://namespace-example.fr/s...e/technique/version/ged-sharepoint/1.1';
expect(() => {
_TreeHelperPipe.transform(item, 60, '...').toBe(expectedItem);
});
})
);
});
});
Error: StaticInjectorError[TreeHelperPipe]: NullInjectorError: No
provider for TreeHelperPipe!
What's wrong with my test ?
Thanks for your help.
In this line:
inject([TreeHelperPipe], (_TreeHelperPipe: any) => {
You're trying to inject a Pipe, but you didn't create any module before that. That's why Angular doesn't find the pipe you're trying to inject.
That said, here you do not need a module and you can just create an instance as you've done here:
pipe = new TreeHelperPipe();
Then make your assertions by calling pipe.transform(your, arguments, here) (and do not forget to remove the line with inject).