我试图将asp.net mvc与angular 2应用程序集成。我知道这并不理想,但我被要求将一些现有的Mvc功能(想想大遗产应用程序)整合到一个全新的Angular 2水疗中心。
我希望能够做的是拥有一个包含角度组件的cshtml视图,以及纯粹的mvc内容......
<side-bar></side-bar>
<action-bar></action-bar>
@{
Html.RenderPartial("_SuperLegacyPartialView");
}
我很难找到办法做到这一点。这篇博文看起来很有希望 - http://www.centare.com/tutorial-angular2-mvc-6-asp-net-5/。它使用了一个指向由Mvc和AsyncRoute呈现的路径的templateUrl值,但在Angular 2中它们都不再有效。这篇文章看起来很有前途 - http://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html,但它也使用了AsyncRoute,这是弃用。
这在Angular 1中非常容易。我们曾经手动将角度引导到Razor视图中,或者将局部视图渲染为组件/指令的templateUrl。在使用Webpack的最新Angular 2中执行此操作的最佳方法是什么?
答案 0 :(得分:11)
我想出了一个满足我当时需求的解决方案。我正在使用带有WebPack的angular-cli,这符合我的需求。我不明白我见过的所有使用“templateUrl:'/ Template / Index'”的例子,其中路径是MVC视图的路径。这根本不起作用,因为在WebPack创建的任何捆绑视图中都找不到路径。也许那些人没有使用angular-cli和WebPack。
此stackoverflow答案 - How can I use/create dynamic template to compile dynamic Component with Angular 2.0?在创建以下指令时非常有用。该指令将获取mvc局部视图的输出并进行编译。它允许发生Razor /服务器逻辑,并且还可以编译一些角度。虽然,实际上包含这个MVC部分内的其他组件是有问题的。如果你这样做,请让我知道你做了什么。在我的情况下,我只需要进行服务器渲染,并将其放置在我的Angular 2 spa中。
<强> MvcPartialDirective 强>
import {
Component,
Directive,
NgModule,
Input,
ViewContainerRef,
Compiler,
ComponentFactory,
ModuleWithComponentFactories,
ComponentRef,
ReflectiveInjector, OnInit, OnDestroy
} from '@angular/core';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import {Http} from "@angular/http";
import 'rxjs/add/operator/map';
export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
@NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
class DynamicHtmlModule { }
return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
});
}
@Directive({ selector: 'mvc-partial' })
export class MvcPartialDirective implements OnInit, OnDestroy {
html: string = '<p></p>';
@Input() url: string;
cmpRef: ComponentRef<any>;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler, private http: Http) { }
ngOnInit() {
this.http.get(this.url)
.map(res => res.text())
.subscribe(
(html) => {
this.html = html;
if (!html) return;
if(this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: this.html,
});
createComponentFactory(this.compiler, compMetadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
});
},
err => console.log(err),
() => console.log('MvcPartial complete')
);
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
some-component.html 中的(假设您的mvc应用与您的水疗中心共享域名)
<mvc-partial [url]="'/stuffs/mvcstuff'"></mvc-partial>
<强> MvcStuff.cshtml 强>
@{
ViewBag.Title = "This is some MVC stuff!!!";
}
<div>
<h2>MVC Stuff:</h2>
<h4>@ViewBag.Title</h4>
<h2>Angular Stuff:</h2>
<h4>{{1 + 1}}</h4>
</div>
StuffsController.cs 中的
public PartialViewResult MvcStuff() => PartialView();
答案 1 :(得分:1)
我是这样做的。
@Component({
templateUrl: '/Template/Index'
})
export class TemplateComponent {}
&#34; /模板/索引&#34;是MVC控制器中的URL,然后是方法。
public IActionResult Index()
{
return PartialView();
}
我的问题是我不知道如何在每次加载时刷新视图以调用控制器方法。
答案 2 :(得分:0)
我需要在我的angular 4应用程序中使用MVC PartialView html,由HttpClient .get方法调用。
我使用了AMD's post
将我的局部视图转换为html字符串。我在一个容器json对象中返回了它,并将其设置为一个变量,在我的页面上设置div的html ...这样:
...in the template
<div class="files" [innerHtml]="myTemplate">
</div>
... in the component .ts file
export interface htmldata {
html: string;
}
... inside component
getDivHtml(path: string): Promise<htmldata> {
return this.http
.get<htmldata>(`${this.baseUrl}/MVC/Index?path=` + path , { withCredentials: true })
.toPromise();
}
ngOnInit() {
this.getDivHtml('').then(
data => { this.loadData(data); },
).catch( error => { console.log(error); });
}
loadData(data: htmldata) {
this.myTemplate = data.html;
}
...在服务器上
public class HtmlReturn
{
public string html { get; set; }
}
[Produces("application/json")]
[Route("api/MVC/[action]")]
public class MVCController : Controller
{
private readonly ViewRender view;
public MVCController(ViewRender view)
{
this.view = view;
}
public IActionResult Index(string path)
{
data.html = this.view.Render("viewpath", viewModel);
return Json(data);
}
}
请注意:这仅适用于不需要事件监听器的静态html。我无法使用renderer2将加载的html添加点击事件,虽然我不是专家,但它可能是可能的。
您需要创建ViewRender类并在startup.cs文件中添加注入指令,如AMDs post
所示答案 3 :(得分:0)
对于使用Angular 7的用户,您将需要稍作更改才能使其正常工作。
在 MvcPartialDirective 中:
将Http更新为HttpClient,使其显示为:
import { HttpClient } from '@angular/common/http';
在ngOnInit()中,指定responseType:
this.http
.get(this.url, {responseType: "text"})...
更新到管道:
.pipe(map(res => res.toString()))
(请注意toString()而不是.text())
(可选)在指令说明中使用app
前缀:
@Directive({
selector: 'appActionResult'
})
最终结果:
import {
Component,
Directive,
NgModule,
Input,
ViewContainerRef,
Compiler,
ComponentFactory,
ModuleWithComponentFactories,
ComponentRef,
ReflectiveInjector, OnInit, OnDestroy
} from '@angular/core';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent { };
const decoratedCmp = Component(metadata)(cmpClass);
@NgModule({
imports: [CommonModule, RouterModule],
declarations: [decoratedCmp],
schemas: [NO_ERRORS_SCHEMA] })
class DynamicHtmlModule { }
return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
.then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
});
}
@Directive({
selector: 'appActionResult'
})
export class ActionResultDirective implements OnInit, OnDestroy {
html = '<p></p>';
@Input() url: string;
cmpRef: ComponentRef<any>;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler, private http: HttpClient) {}
ngOnInit() {
this.http
.get(this.url, {responseType: "text"})
.pipe(map(res => res.toString()))
.subscribe(
(html) => {
this.html = html;
if (!html) { return; }
if (this.cmpRef) {
this.cmpRef.destroy();
}
const compMetadata = new Component({
selector: 'dynamic-html',
template: this.html,
});
createComponentFactory(this.compiler, compMetadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.cmpRef = this.vcRef.createComponent(factory, 0, injector, []);
});
},
err => console.log(err),
() => console.log('MvcPartial complete')
);
}
ngOnDestroy() {
if (this.cmpRef) {
this.cmpRef.destroy();
}
}
}
答案 4 :(得分:-1)