2017-01-04 22 views
6

Próbuję zintegrować asp.net mvc z aplikacją kątową 2. Rozumiem, że nie jest to idealne rozwiązanie, ale poproszono mnie o zintegrowanie niektórych istniejących funkcji Mvc (myślę, że starsza aplikacja) w zupełnie nowym spa Angular 2.Jak renderować widok asp.net mvc na kątowy 2?

Co chciałbym być w stanie zrobić, to mieć widok cshtml który ma kanciaste elementy w nim, a także czystą mvc rzeczy ...

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

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

jestem stara się znaleźć jakiś sposób, aby Zrób to. Ten wpis na blogu wyglądał obiecująco - http://www.centare.com/tutorial-angular2-mvc-6-asp-net-5/. Użyto wartości templateUrl, która wskazywała ścieżkę renderowaną przez Mvc, a także AsyncRoute, ale żadna z nich już nie działa w Angular 2. Ten post również wyglądał obiecująco - http://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html, ale używa również AsyncRoute, który jest przestarzały.

To było bardzo łatwe w ustawieniu kątowym 1. Zwykle ręcznie ładowaliśmy kątowo w widoku gilotyny lub wyświetlamy częściowy widok jako szablonUrl komponentu/dyrektywy. Jaki jest najlepszy sposób na zrobienie tego w najnowszym Angular 2, który używa Webpacka?

Odpowiedz

9

Wymyśliłem rozwiązanie, które zaspokoiło moje potrzeby w tym czasie. Używam angular-cli z WebPack, a to działało na moje potrzeby. Nie rozumiem wszystkich przykładów, które widziałem, aby używać "templateUrl: '/ Template/Index" ", gdzie ścieżka jest ścieżką do widoku MVC. To po prostu nie działa, ponieważ nie można znaleźć ścieżki w żadnym z dołączonych widoków tworzonych przez WebPack. Może ci ludzie nie używają angular-cli i WebPack.

Ta odpowiedź stackoverflow - How can I use/create dynamic template to compile dynamic Component with Angular 2.0? była bardzo pomocna przy tworzeniu poniższej dyrektywy. Ta dyrektywa pobierze wynik częściowego widoku mvc i skompiluje go. Pozwala to na uzyskanie logiki Razor/serwer, a także trochę kompilacji kątowej. Chociaż w rzeczywistości włączenie innych elementów w tym częściowym MVC było problematyczne. Jeśli to zadziała, daj mi znać, co zrobiłeś. W moim przypadku potrzebowałem renderowania serwera i umieszczenia go dokładnie tam, gdzie chciałem, w moim 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(); 
    } 
    } 
} 

w pewne-component.html (zakładając swoje udziały MVC aplikacji domenę ze swoim 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> 

w StuffsController.cs

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

To jest właściwa odpowiedź. Działa jak marzenie. Wydaje mi się, że czasami warto wstępnie renderować szablony kątowe na serwerze, aby można było łatwo renderować Nazwę użytkownika lub wykonywać inną logikę biznesową specyficzną dla tego użytkownika (uprawnienia itp.). –

+0

To jedyny sposób, aby to osiągnąć? – k11k2

+0

Pobranie ''undefined' nie daje się wpisać" ComponentFactory "' error – k11k2

-1
+0

Dzięki za odpowiadać, ale żadna z powyższych ćwiczeń rozwiązuje moje pytanie, a to dlatego, że ma tak trudno znaleźć odpowiedź. Jak każdy inny samouczek w sieci, te właśnie opisują, jak skonfigurować Angular Spa w MVC. Nie odnoszą się do renderowania częściowych i kątowych MVC na tej samej stronie. –

1

zrobiłem to w ten sposób.

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

"/ Template/Index" to adres URL kontrolera MVC, a następnie metoda.

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

Mój problem polega na tym, że nie wiem, jak odświeżyć widok, aby wywołać metodę sterownika za każdym razem, gdy jest ładowany.

+1

to zdecydowanie nie działa z pakietem sieci Web. –

+0

Dzięki to działa dla mnie! –

0

Musiałem użyć MVC PartialView html w moim kątową 4 wniosku, zwana metodą HttpClient .get.

użyłem AMD's post

przekonwertować mój częściowy widok na ciąg html. Wróciłem to w json obiektu kontenera i ustaw go do zmiennej, które wyróżniają html div na moim 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; 
    } 

... na serwerze

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); 
     } 
} 

Uwaga : działa to dobrze tylko w przypadku statycznego html, który nie potrzebuje programów nasłuchujących zdarzenia. Nie udało mi się dodać zdarzeń kliknięcia do załadowanego html przy pomocy renderer2, chociaż nie jestem ekspertem i może to być możliwe.

Musisz utworzyć klasę ViewRender i dodać dyspozycję wtrysku do pliku startup.cs jak pokazano na AMDs postu