2017-01-04 35 views
6

我正在尝试将asp.net mvc与角度2应用程序集成。我知道这并不理想,但我被要求将一些现有的Mvc功能(认为大型的传统应用程序)整合到一个全新的Angular 2 spa中。如何将asp.net mvc视图渲染为角度2?

我想做什么就能做的是有一个其中有角分量,以及纯MVC的东西一CSHTML视图...

<side-bar></side-bar> 
<action-bar></action-bar> 

@{ 
    Html.RenderPartial("_SuperLegacyPartialView"); 
} 

我努力寻找任何方式做这个。这篇博文看起来很有前途 - http://www.centare.com/tutorial-angular2-mvc-6-asp-net-5/。它使用了一个指向Mvc渲染的路径的templateUrl值,以及AsyncRoute,但Angular 2中没有任何工作。这篇文章看起来很有前途 - http://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html,但它也使用了AsyncRoute,这已被弃用。

这在Angular 1中非常容易使用。我们曾经手动将角引导到Razor视图中,或者将部分视图渲染为组件/指令的templateUrl。在最新的使用Webpack的Angular 2中做这件事的最好方法是什么?

回答

9

我想出了一个满足我当时需求的解决方案。我用WebPack使用angular-cli,并且这可以满足我的需求。我不明白我见过的所有使用“templateUrl:'/ Template/Index'”的例子,其中路径是MVC视图的路径。这根本行不通,因为无法在WebPack创建的任何捆绑视图内找到路径。也许这些人不使用angular-cli和WebPack。

这个计算器的回答 - 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(); 
    } 
    } 
} 

一些-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> 

in StuffsController。CS

public PartialViewResult MvcStuff() => PartialView(); 
+0

这是正确的答案。奇迹般有效。我认为有时在服务器上预先呈现Angular模板是有意义的,因此您可以轻松呈现UserName或在其中执行其他用户特定的业务逻辑(权限等)。 –

+0

这是实现它的唯一方法吗? – k11k2

+0

得到''未定义'不可分配给类型'ComponentFactory ''错误 – k11k2

1

我做了这个样子。

@Component({ 
    templateUrl: '/Template/Index' 
}) 
export class TemplateComponent {} 

“/模板/指数” 是在你的MVC控制器的URL,然后方法。

public IActionResult Index() 
    { 
    return PartialView(); 
    } 

我的问题是我不知道如何刷新每次调用控制器方法的视图加载。

+1

这绝对不适用于webpack。 –

+0

谢谢它适合我! –

0

我需要使用MVC PartialView HTML在我的角度4的应用程序,通过HttpClient的。获得方法调用。

我用AMD's post

我的局部视图转换为HTML字符串。我在一个容器json对象返回这一点,并将它设置成设置一个div的HTML我page..thus变量:

...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后显示