Angular 如何将数据从子路由传递到父路由(使用提交时的表单)

Angular 如何将数据从子路由传递到父路由(使用提交时的表单),angular,Angular,我有一个组件,其中包含一个带有新费用按钮的费用列表。单击它将转到其子路由,如下所示: <a [routerLink]="['./new']">New Expense</a> 我在网上看到的示例中,输入与表单位于同一组件中,因此他们可以在使用http post请求将其添加到数据库中后,将其简单地“推”到列表中,这样它也可以直观地“就地”更新 我的目标是复制这种效果。我想把它添加到列表中,这样用户就可以看到它,而不仅仅是将它发布到数据库中。是否有办法将此费用从子路由发送到父

我有一个组件,其中包含一个带有新费用按钮的费用列表。单击它将转到其子路由,如下所示:

<a [routerLink]="['./new']">New Expense</a>
我在网上看到的示例中,输入与表单位于同一组件中,因此他们可以在使用http post请求将其添加到数据库中后,将其简单地“推”到列表中,这样它也可以直观地“就地”更新

我的目标是复制这种效果。我想把它添加到列表中,这样用户就可以看到它,而不仅仅是将它发布到数据库中。是否有办法将此费用从子路由发送到父路由,或者我是否应该将其添加到数据库中,并让
费用组件
重新加载列表,而不是仅在
ngOnInit()期间发生?下面是我相信的相关代码。我从中移除了一些东西来去除杂乱,所以它实际上不会运行。我只是在寻找最好的方法,而不是真正的代码

例如,我知道如果在模板中我没有使用路由,而是像这样调用子组件
。有一种使用发射器的方法,所以我使用route来显示此组件是错误的吗

包含列表的费用组成部分

@组件({
选择器:'应用程序费用',
templateUrl:“./expenses.component.html”,
样式URL:['./expenses.component.css']
})
导出类支出组件实现OnInit{
费用:费用[];
建造商(私人费用服务:费用服务){
}
恩戈尼尼特(){
this.expenseService.getExpenses()
.认购(费用=>this.expenses=费用);
}
getExpense(id:编号){
//log(this.expenseService.getExpense(id));
}
}
包含以下表单的新费用组成部分

@组件({
选择器:“应用程序新费用”,
templateUrl:“./new expense.component.html”,
样式URL:['./new expense.component.css']
})
导出类NewExpenseComponent实现OnInit{
模式:费用;
类型:字符串[];
建造师(
专用路由器:路由器,
私人支出服务:支出服务{}
恩戈尼尼特(){
该模型=新费用(0,40,“维珍移动”,“2019/10/12”,“固定”);
this.types=[“固定”、“周期”、“变量”];
}
提交(金额、地点、日期){
var费用=新费用(6,金额、地点、日期,“固定”);
此.expenseService.addExpense(费用).订阅(
);
}
}
费用服务

@可注入({
providedIn:'根'
})
出口类费用服务{
费用$:可观察到的;
构造函数(私有http:HttpClient){}
getExpenses():可观察{
this.expenses$=this.http.get('http://localhost:8000/expenses');
退回这个。费用$;
}
附加费用(费用:费用):可观察{
返回此.http.post(“http://localhost:8000/expenses“,费用);
}
getExpense(id:编号|字符串){
返回此.getExpenses()管道(
映射((费用:费用[])=>expenses.find(费用=>Expense.id===+id))
);
}
}

是的,您可以修改服务以保留费用列表

下面是我的一项服务的一个例子。这还会通知组件“选定产品”应更改为列表中新添加的产品

@Injectable({
  providedIn: 'root'
})
export class ProductService {
    private productsUrl = 'api/products';
    private products: IProduct[];

    private selectedProductSource = new BehaviorSubject<IProduct | null>(null);
    selectedProductChanges$ = this.selectedProductSource.asObservable();

    constructor(private http: HttpClient) { }

    getProducts(): Observable<IProduct[]> {
        if (this.products) {
            return of(this.products);
        }
        return this.http.get<IProduct[]>(this.productsUrl)
                        .pipe(
                            tap(data => console.log(JSON.stringify(data))),
                            tap(data => this.products = data),
                            catchError(this.handleError)
                        );
    }

    createProduct(product: IProduct, headers: HttpHeaders): Observable<IProduct> {
      return this.http.post<IProduct>(this.productsUrl, product,  { headers: headers} )
                    .pipe(
                        tap(data => console.log('createProduct: ' + JSON.stringify(data))),
                        tap(data => {
                            this.products.push(data);
                        }),
                        catchError(this.handleError)
                    );
}
}
@可注入({
providedIn:'根'
})
出口类产品服务{
private productsUrl=‘api/产品’;
私人产品:IPProduct[];
private selectedProductSource=new BehaviorSubject(空);
selectedProductChanges$=this.selectedProductSource.asObservable();
构造函数(私有http:HttpClient){}
getProducts():可观察{
如果(本产品){
(本产品)的退货;
}
返回this.http.get(this.productsUrl)
.烟斗(
点击(data=>console.log(JSON.stringify(data)),
点击(数据=>this.products=数据),
catchError(this.handleError)
);
}
createProduct(产品:IPProduct,标题:HttpHeaders):可观察{
返回this.http.post(this.productsUrl,product,{headers:headers})
.烟斗(
点击(data=>console.log('createProduct:'+JSON.stringify(data)),
点击(数据=>{
本.产品.推送(数据);
}),
catchError(this.handleError)
);
}
}
请注意,
createProduct
方法随后将数据推送到列表中

@Injectable({
  providedIn: 'root'
})
export class ProductService {
    private productsUrl = 'api/products';
    private products: IProduct[];

    private selectedProductSource = new BehaviorSubject<IProduct | null>(null);
    selectedProductChanges$ = this.selectedProductSource.asObservable();

    constructor(private http: HttpClient) { }

    getProducts(): Observable<IProduct[]> {
        if (this.products) {
            return of(this.products);
        }
        return this.http.get<IProduct[]>(this.productsUrl)
                        .pipe(
                            tap(data => console.log(JSON.stringify(data))),
                            tap(data => this.products = data),
                            catchError(this.handleError)
                        );
    }

    createProduct(product: IProduct, headers: HttpHeaders): Observable<IProduct> {
      return this.http.post<IProduct>(this.productsUrl, product,  { headers: headers} )
                    .pipe(
                        tap(data => console.log('createProduct: ' + JSON.stringify(data))),
                        tap(data => {
                            this.products.push(data);
                        }),
                        catchError(this.handleError)
                    );
}
}
您可以在此处找到完整的代码:


或者,您也可以查看NgRx,它是Angular的状态管理库。

来自@DeborahK:)我有一个建议或问题,您不认为最好将本质上是缓存功能的东西移到服务之外,并通过拦截器捕获它。这可能允许一个更薄的类和一个可重用的功能来满足任何缓存需求!关于拦截器。对Brice Wilson在他的Pluralsight课程中构建了一个:答案非常有效。将我的费用变量初始化为Expense[]类型,而不是Observable,并稍微调整了getExpense()方法,以便在addExpense()方法中可以执行类似于.expenses.push(费用)的操作。还感谢您提供的所选费用提示。@DeborahK,您的pluralsite课程帮助我了解Angular的最新知识,因为您,我目前在澳大利亚政府担任Angular+.NET的全栈开发者。通过这篇文章,你再一次启发了我。非常感谢你。