如何将 asp.net mvc 视图渲染为 angular 2?
How to render asp.net mvc view into angular 2?
我正在尝试将 asp.net mvc 与 angular 2 应用程序集成。我知道这并不理想,但我被要求将一些现有的 Mvc 功能(想想大型遗留应用程序)集成到一个全新的 Angular 2 spa 中。
我希望能够做的是拥有一个包含 angular 组件以及纯 mvc 内容的 cshtml 视图...
<side-bar></side-bar>
<action-bar></action-bar>
@{
Html.RenderPartial("_SuperLegacyPartialView");
}
我正在努力寻找任何方法来做到这一点。此博客 post 看起来很有前途 - http://www.centare.com/tutorial-angular2-mvc-6-asp-net-5/. It used a templateUrl value that pointed to a path rendered by Mvc, as well as AsyncRoute, but none of that works anymore in Angular 2. This post looked promising as well - http://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html,但它也使用 AsyncRoute,但已弃用。
这在 Angular 中曾经非常简单 1. 我们过去要么手动 bootstrap angular 到 Razor 视图中,要么将部分视图呈现为 [= 的 templateUrl =22=]。在使用 Webpack 的最新 Angular 2 中执行此操作的最佳方法是什么?
使用 Systemjs:
https://github.com/VahidN/MVC5Angular2
使用网页包:
http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/
我是这样做的
@Component({
templateUrl: '/Template/Index'
})
export class TemplateComponent {}
"/Template/Index"是你的MVC Controller中的URL,然后是方法。
public IActionResult Index()
{
return PartialView();
}
我的问题是我不知道每次刷新视图以调用控制器方法是如何加载的。
我想出了一个解决方案,满足了我当时的需求。我将 angular-cli 与 WebPack 一起使用,这可以满足我的需要。我不明白我看到的所有示例都说要使用 "templateUrl: '/Template/Index'",其中路径是 MVC 视图的路径。这根本行不通,因为在 WebPack 创建的任何捆绑视图中都找不到该路径。也许那些人没有使用 angular-cli 和 WebPack。
这个 Whosebug 答案 - 对创建以下指令非常有帮助。该指令将获取 mvc 局部视图的输出并对其进行编译。它允许发生 Razor/server 逻辑,并且还可以编译一些 angular 。虽然,实际上在这个 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();
}
}
}
in some-component.html(假设您的 mvc 应用与您的 spa 共享域)
<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();
我需要在我的 angular 4 应用程序中使用 MVC PartialView html,由 HttpClient .get 方法调用。
我用了
将我的部分视图转换为 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 class 并将注入指令添加到 startup.cs 文件中,如 post
所示
对于 Angular 7 的那些人,您需要稍微更改已接受的答案才能使其生效。
在MvcPartialDirective中:
将 Http 更新为 HttpClient,使其显示为:
import { HttpClient } from '@angular/common/http';
在 ngOnInit() 中,指定响应类型:
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();
}
}
}
我正在尝试将 asp.net mvc 与 angular 2 应用程序集成。我知道这并不理想,但我被要求将一些现有的 Mvc 功能(想想大型遗留应用程序)集成到一个全新的 Angular 2 spa 中。
我希望能够做的是拥有一个包含 angular 组件以及纯 mvc 内容的 cshtml 视图...
<side-bar></side-bar>
<action-bar></action-bar>
@{
Html.RenderPartial("_SuperLegacyPartialView");
}
我正在努力寻找任何方法来做到这一点。此博客 post 看起来很有前途 - http://www.centare.com/tutorial-angular2-mvc-6-asp-net-5/. It used a templateUrl value that pointed to a path rendered by Mvc, as well as AsyncRoute, but none of that works anymore in Angular 2. This post looked promising as well - http://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html,但它也使用 AsyncRoute,但已弃用。
这在 Angular 中曾经非常简单 1. 我们过去要么手动 bootstrap angular 到 Razor 视图中,要么将部分视图呈现为 [= 的 templateUrl =22=]。在使用 Webpack 的最新 Angular 2 中执行此操作的最佳方法是什么?
使用 Systemjs: https://github.com/VahidN/MVC5Angular2 使用网页包: http://blog.stevensanderson.com/2016/10/04/angular2-template-for-visual-studio/
我是这样做的
@Component({
templateUrl: '/Template/Index'
})
export class TemplateComponent {}
"/Template/Index"是你的MVC Controller中的URL,然后是方法。
public IActionResult Index()
{
return PartialView();
}
我的问题是我不知道每次刷新视图以调用控制器方法是如何加载的。
我想出了一个解决方案,满足了我当时的需求。我将 angular-cli 与 WebPack 一起使用,这可以满足我的需要。我不明白我看到的所有示例都说要使用 "templateUrl: '/Template/Index'",其中路径是 MVC 视图的路径。这根本行不通,因为在 WebPack 创建的任何捆绑视图中都找不到该路径。也许那些人没有使用 angular-cli 和 WebPack。
这个 Whosebug 答案 -
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();
}
}
}
in some-component.html(假设您的 mvc 应用与您的 spa 共享域)
<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();
我需要在我的 angular 4 应用程序中使用 MVC PartialView html,由 HttpClient .get 方法调用。
我用了
将我的部分视图转换为 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 class 并将注入指令添加到 startup.cs 文件中,如
对于 Angular 7 的那些人,您需要稍微更改已接受的答案才能使其生效。
在MvcPartialDirective中:
将 Http 更新为 HttpClient,使其显示为:
import { HttpClient } from '@angular/common/http';
在 ngOnInit() 中,指定响应类型:
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();
}
}
}