web-dev-qa-db-ja.com

asp.netmvcビューをangular 2にレンダリングする方法は?

Asp.netmvcをangular 2アプリケーションと統合しようとしています。これは理想的ではないことは理解していますが、既存のMvc機能を統合するように求められています(大きなレガシーアプリを考えてください)真新しいAngular 2スパ。

私ができるようにしたいのは、angularコンポーネントと純粋な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によってレンダリングされたパスとAsyncRouteを指すtemplateUrl値を使用しましたが、Angular 2。この投稿も有望に見えました http ://gbataille.github.io/2016/02/16/Angular2-Webpack-AsyncRoute.html ただし、AsyncRouteも使用しているため、非推奨です。

これは、Angular 1。では非常に簡単でした。手動でbootstrap angular Razor Viewに入れるか、またはコンポーネント/ディレクティブのtemplateUrlとして部分ビューをレンダリングします。Webpackを使用する最新のAngular 2でこれを行うための最良の方法は何ですか?

7
Tim Hardy

当時の自分のニーズを満たすソリューションを思いつきました。私はWebPackでangular-cliを使用していますが、これは私のニーズに合っていました。パスがMVCビューへのパスである、「templateUrl: '/ Template/Index'」を使用するという、私が見たすべての例を理解していません。 WebPackが作成するバンドルされたビューのいずれにもパスが見つからないため、これは単に機能しません。たぶんそれらの人々はangular-cliとWebPackを使用していません。

このstackoverflowの回答-- 動的テンプレートを使用/作成してAngular 2.0? で動的コンポーネントをコンパイルするにはどうすればよいですか?)==は、次のディレクティブの作成に非常に役立ちました。このディレクティブは、 mvcパーシャルビューの出力とコンパイル。これにより、Razor /サーバーロジックが実行され、一部のangularもコンパイルされます。ただし、実際には、このMVCパーシャル内に他のコンポーネントが含まれていました。問題があります。問題が発生した場合は、何をしたかをお知らせください。私の場合は、サーバーレンダリングを実行し、それを必要な場所に正確に配置する必要がありましたAngular 2スパ。

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

insome-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>

inStuffsController.cs

public PartialViewResult MvcStuff() => PartialView();
12
Tim Hardy

こんな感じでした。

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

「/ Template/Index」は、MVCコントローラーのURLであり、次にメソッドです。

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

私の問題は、ロードされるたびにビューを更新してコントローラーメソッドを呼び出す方法がわからないことです。

1
Federico

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()))(。text()の代わりにtoString()に注意してください)

オプションで、ディレクティブ指定に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();
    }
  }
}
_
1
taylorswiftfan

HttpClient.getメソッドによって呼び出されるangular 4アプリケーションでMVCPartialViewhtmlを使用する必要がありました。

私は使用しました AMDの投稿

部分ビューを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にクリックイベントを追加できませんでした。

AMDs postに示すように、ViewRenderクラスを作成し、startup.csファイルにインジェクション命令を追加する必要があります。

0
davaus