>以前,我们创建了自己的firestore getters来返回适当的观察力,从而将诺言转变为可冷观察的诺言。今天,让我们继续使用其他命令,以正确地映射我们的数据。
>>现在我们不依赖rxfire返回映射的文档id,我们将创建自己的转换器。
“ firestore有一个内置的converter withconverter to conconter tor map to and firestore。不,谢谢。我们将从这里拿走。getdoc()返回具有id的文档napshot,以及上述数据()。 getdocs()返回带有docs数组的querysnapshot,除其他外,这是返回的documentsnapshot对象。我们的类别模型现在看起来像这样:
// category.model
// mapping new instance
export interface icategory {
name: string | null;
id: string | null;
key?: string;
}
// static class or export functions, it's a designers choice
export class category {
public static newinstance(data: querydocumentsnapshot): icategory {
if (data === null) {
return null;
}
const d = data.data();
return {
id: data.id,
name: d['name'],
key: d['key']
};
}
// receives querysnapshot and maps out the `data() ` and id
public static newinstances(data: querysnapshot): icategory[] {
// read docs array
return data.docs.map(n => category.newinstance(n));
}
}
// category.service
getcategories(params: iwhere[] = []): observable<icategory[]> {
// ...
return from(getdocs(_query)).pipe(
map((res: querysnapshot) => {
// here map
return category.newinstances(res);
})
);
}
getcategory(id: string): observable<icategory> {
return from(getdoc(doc(this.db, 'categories', id))).pipe(
map((res: documentsnapshot) => {
// map
return category.newinstance(res);
}),
);
}
创建文档
// components/categories.list
addnew() {
// read form:
const newcat: partial<icategory> = this.fg.value;
this.categoryservice.createcategory(newcat).subscribe({
next: (res) => {
// the category list should be updated here
console.log(res);
}
});
}
// category.service
createcategory(category: partial<icategory>): observable<any> {
return from(adddoc(collection(this.db, 'categories'), category)).pipe(
map(res => {
// i have nothing but id!
return {...category, id: res.id};
})
);
}
>可能看起来不错,但是我不希望在不浏览映射器的情况下直接使用id,解决方案可以像单独的映射器一样简单,或者我们可以稍微适应newinstance
// category.model
// adjust newinstance to accept partial category
public static newinstance(data: documentsnapshot | partial<icategory>, id?: string): icategory {
if (data === null) {
return null;
}
const d = data instanceof documentsnapshot ? data.data() : data;
return {
id: data.id || id, // if data.id doesnt exist (as in adddoc)
name: d['name'],
key: d['key']
};
}
// category.service
createcategory(category: partial<icategory>): observable<icategory> {
return from(adddoc(collection(this.db, 'categories'), category)).pipe(
map(res => {
// update to pass category and res.id
return category.newinstance(category, res.id);
}),
);
}
>以下方法是如此相同,如果您不区分它们,您可能会在50岁之前失去头发。因此,我决定列出它们,然后忘记它们。
中保存提供的id
adddoc(collection(this.db,'cantories'),{... newcategory});添加带有自动生成id的文档(这是doc(collection ...)然后setdoc())// find document reference, or create it with new id const categoryref = doc(this.db, 'categories', '_somedocumentreferenceid'); // create a document reference with auto generated id const categoryref = doc(collection(this.db, 'categories'));
// then use the returned reference to setdoc, to add a new document
setdoc(categoryref, {name: 'bubbles', key: 'bubbles'});
// pass partial document with options: merge to partially update an existing document
setdoc(existingcategoryref, {name: 'bubble'}, {merge: true});
>
// add a new documnet with a new generated id
adddoc(collection(this.db, 'categories'), {name: 'bubbles', key: 'bubbles'});
// update and existing document, this will throw an error if non existent
updatedoc(existingcategoryref, {name: 'bubbles'})
的另一种方法
// an alternative way to create
createcategory(category: partial<icategory>): observable<icategory> {
// new auto generated id
const ref = doc(collection(this.db, 'categories'));
return from(setdoc(ref, category)).pipe(
map(_ => {
// response is void, id is in original ref
return category.newinstance(category, ref.id);
})
);
}
>在上面的构建中,我为类别详细信息创建了一个快速表单以允许更新。我仍然会通过所有字段,但是我们总是可以通过部分字段。
>
// category.sevice
// id must be passed in category
updatecategory(category: partial<icategory>): observable<icategory> {
return from(updatedoc(doc(this.db, 'categories', category.id), category)).pipe(
map(_ => {
// response is void
// why do we do this? because you never know in the future what other changes you might need to make before returning
return category.newinstance(category);
})
);
}
>
使用它,收集表格,并捕获id:
// categories/list.component
update(category: icategory) {
// gather field values
const cat: partial<icategory> = this.ufg.value;
// make sure the id is passed
this.categoryservice.updatecategory({...cat, id: category.id}).subscribe({
next: (res) => {
console.log(res); // this has the same category after update
}
});
}
这是直截了当的,我们可能会选择退还布尔值以获得成功。
>
// category.sevice
deletecategory(id: string): observable<boolean> {
return from(deletedoc(doc(this.db, 'categories', id))).pipe(
// response is void, but we might want to differentiate failures later
map(_ => true)
);
}
我们只是通过传递id
来称其为
// category/list.component
delete(category: icategory) {
this.categoryservice.deletecategory(category.id).subscribe({
next: (res) => {
console.log('success!', res);
}
});
}
>我们创建了一个iwher模型,以允许将任何查询传递到我们的类别列表。但是,我们应该控制在模型中查询的字段,并保护我们的组件免受现场变化的影响。我们还应该控制可以询问的内容,以及如何始终领先于火箱上的任何隐藏价格。
// where.model
// the param fields object (yes its plural)
export interface ifieldoptions {
label?: string; // exmaple
key?: string;
// other example fields
month?: date;
recent?: boolean;
maxprice?: number;
}
// map fields to where conditions of the proper firestore keys
export const maplistoptions = (options?: ifieldoptions): iwhere[] => {
let c: any[] = [];
if (!options) return [];
if (options.label) {
// mapping label to name
c.push({ fieldpath: 'name', opstr: '==', value: options.label });
}
if(options.key) {
c.push({ fieldpath: 'key', opstr: '==', value: options.key });
}
// maxprice is a less than or equal operator
if (options.maxprice) {
c.push({ fieldpath: 'price', opstr: '<=', value: options.maxprice });
}
if (options.month) {
// to implement, push only data of the same month
c.push(...mapmonth(options.month));
}
if (options.recent) {
const lastweek = new date();
lastweek.setdate(lastweek.getdate() - 7);
// things that happened since last week:
c.push({ fieldpath: 'date', opstr: '>=', value: lastweek });
}
return c;
}
// category.sevice
// accept options of specific fields
getcategories(params?: ifieldoptions): observable<icategory[]> {
// translate fields to where:
const _where: any[] = (mapfieldoptions(fieldoptions))
.map(n => where(n.fieldpath, n.opstr, n.value));
// pass the where to query
const _query = query(collection(this.db, this._url), ..._where);
// ... getdocs
}
// example usage
something$ = someservice.getlist({maxprice: 344});
>
// example
something$ = someservice.getlist({recent: true});
另一个示例是获取日期,firestore直接处理javascript日期:
// where.model
const mapmonth = (month: date): iwhere[] => {
const from = new date(month);
const to = new date(month);
from.setdate(1);
from.sethours(0, 0, 0, 0);
to.setmonth(to.getmonth() + 1);
to.sethours(0, 0, 0, 0); // the edge of next month, is last day this month
let c: iwhere[] = [
{ fieldpath: 'date', opstr: '>=', value: from },
{ fieldpath: 'date', opstr: '<=', value: to }
];
return c;
};
时间戳
firestore参考时间戳。
>
// somemodel
// use timestamp class to map from and to dates
const jsdate = new date();
// adddoc with
const newdata = {
fbdate: timestamp.fromdate(jsdate)
}
// documentsnapshot returns data() with date field, the type is timestamp
// use todate to convert to js date
return data['fbdate'].todate();
firebase为firestore提供了简单crud的lite版本,到目前为止,我们仅使用了lite版本中的那些。我更改了所有
导入{...}来自'@angular/fire/firestore';
导入{...}来自'@angular/fire/firestore/lite';
>拦截
>使用httpclient,我们使用了截距函数来添加加载效果,那么我们如何使用解决方案来做到这一点?我们可以将所有呼叫调查到一个照顾它的http服务。我们的新服务应该与此有关:
// http.service
@injectable({ providedin: 'root' })
export class httpservice {
public run(fn: observable<any>): observable<any> {
// show loader here
showloader();
// return function as is
return fn
.pipe(
// hide loader
finalize(() => hideloader()),
// debug and catcherrors as well here
);
}
}
// category.service
private httpservice = inject(httpservice);
getcategories(params?: iwhere[]): observable<icategory[]> {
// ...
// wrap in run
return this.httpservice.run(from(getdocs(q)).pipe(
map((res: querysnapshot) => {
return category.newinstances(res);
})
));
}
>上面的一个设计问题是类型检查的丢失,因为内部函数返回可观察到的<any>。这可以用通用
修复
// http.service
// ...
public run<t>(fn: observable<any>): observable<t> {
// ...
}
// category.service
return this.httpService.run<ICategory[]>(from(getDocs(q)).pipe(
map((res: QuerySnapshot) => {
return Category.NewInstances(res);
})
));
你上火了吗?继续说话。还没有结束。
资源
stackblitz project
>在angular
中使用rxj创建负载效果
以上就是将角消防员图书馆放置 - II的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号