2017-01-04 33 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後顯示