Create and Publish Angular 7 App Using Visual Studio and IIS Note: Pulled this from all over, none of it was well documented. **Setup** Locally: Install Windows 10. Locally and on build server: Install VS2017. Install .NET Core 2.1 SDK. Install Node.JS. Build Server: Install TFS 2017 or higher. User guide: https://docs.microsoft.com/en-us/aspnet/core/client-side/spa/angular?view=aspnetcore-2.1&tabs=visual-studio Sample application: TFS/VS2017Test/TestAngularWeb7 (ITBAU-740) To get started, open Visual Studio and create a new web application: File>New Project>.NET CORE>ASP.NET Core Web Application On the next screen, select ‘Angular’ with ASP.NET Core 2.1 Build the solution. Output window will show: Restoring dependencies using 'npm'. This may take several minutes. Do not run app yet. May need to turn off SSL or packages fail to load, if you get cert error. May need to restart VS afterward. npm config set strict-ssl false Run your project. Ensure it runs. Commit/check in to git Note: If you get error ‘ng’ is not a recognizable command, maybe try to install the CLI and restart VS. npm install -g @angular/cli@7.0.2 Delete all content from ClientApp folder Open Node.js command prompt Run 'ng version' and ensure it lists 7 If not: Npm uninstall –g angular-cli Npm cache verify (or npm cache clean if version was < 6) Npm install –g @angular/cli@7.0.2 C:, then Cd to your project folder, i.e. cd C:\TFSUAT\VS2017Test\TestAngularWeb7 Run ng new ClientApp ‘y’ to install routing ‘CSS’ for style sheets To fix intellisense, right click on tsconfig.json properties and set Build Action to Content, then run node.js command prompt and run in ClientApp folder: npm install @types/node --save-dev Set start IIS Express app to ‘Chrome’ and run project to ensure it works In ClientApp/src/Polyfills.ts, uncomment the basic IE polyfills to support IE (under /** IE9, IE10 and IE11 requires all of the following polyfills. **/); otherwise you get error ‘xx is not iterable’ IMPORTANT: In angular.json, change outputPath to: "outputPath": "dist", or you will get a cryptic page not found error when publishing an angular 7 site to IIS remote server: https://stackoverflow.com/questions/55583642/vs2017-angular-7-upgrade-deployment-error-development-mode Set start IIS Express app to ‘Internet Explorer’ and run project to ensure it works Disable (uncheck memory/performance) diagnostics tools (for now) and close that tab. Next run they’ll be off. Re-enable when needed. Page will begin loading. **Windows 7 Support** Untenable. Recommend not using Windows 7 **Site Development** To add a component: Add a folder under ClientApp/src/app such as ‘test’ and copy in app.component.html and ts. Rename/fix .html, .ts, files in the folder. Register your component in ClientApp/src/app/app.module.ts and add to router if a top-level component: import { TestComponent } from './test/test.component'; … @NgModule({ declarations: [ …, TestComponent ], Add to app-routing.module.ts: import { TestComponent } from './test/test.component'; const routes: Routes = [ { path: 'test', component: TestComponent, }]; Run the app. Use F12 to show any runtime errors. To allow typescript debugging, while running open the browser link dropdown and enable browser link. This will only work for Chrome (not Edge/IE). Use the IIS Express debug dropdown to select Chrome. Next, Install angular material (to get forms controls): Run the following from node.js command prompt in your ClientApp folder: Ng add @angular/material Choose indigo-pink No gestures Yes animations In package.json, fix these versions: "@angular/cdk": "7.2.1", "@angular/material": "^7.2.1", Update app.module.ts with references: import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule, MatCheckboxModule, MatDatepickerModule, MatNativeDateModule, MatSelectModule } from '@angular/material'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; imports: […… FormsModule, ReactiveFormsModule, NoopAnimationsModule, MatButtonModule, MatCheckboxModule, MatDatepickerModule, MatNativeDateModule, MatSelectModule, ]) ], Add to ClientApp/src/styles.css: @import "~@angular/material/prebuilt-themes/indigo-pink.css"; Add controls to any html page: <mat-checkbox>check me</mat-checkbox> <input [matDatepicker]="myDatepicker"> <mat-datepicker-toggle [for]="myDatepicker"></mat-datepicker-toggle> <mat-datepicker #myDatepicker></mat-datepicker> <button mat-button color="primary">Primary</button> <mat-form-field> <mat-select placeholder="Toppings" [formControl]="toppings" multiple> <mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option> </mat-select> </mat-form-field> And in the backend .ts of that page: import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'test', templateUrl: './test.component.html' }) export class TestComponent implements OnInit { constructor() { } ngOnInit() { } toppings = new FormControl(); toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato']; } Run the app. Use F12 to show any runtime errors. **Backend** Add standard C# projects for domain,DAL,business layers. **Grids** For advanced grids, can use third party slickgrid. https://github.com/ghiscoding/angular-slickgrid/wiki/HOWTO---Step-by-Step Install Slickgrid by adding to package.json: , "angular-slickgrid": "2.9.6", "jquery": "3.4.1", "bootstrap": "^3.4.1", "font-awesome": "4.7.0", "@ngx-translate/core": "9.1.1", "@ngx-translate/http-loader": "4.0.0" In .angular.json: (angular.json in newer angular), add: “styles” – add: "./node_modules/font-awesome/css/font-awesome.css", "./node_modules/flatpickr/dist/flatpickr.css", "./node_modules/angular-slickgrid/lib/multiple-select/multiple-select.css", "./node_modules/angular-slickgrid/styles/css/slickgrid-theme-bootstrap.css" “scripts” – add: "./node_modules/jquery/dist/jquery.js", "./node_modules/jquery-ui-dist/jquery-ui.min.js", "./node_modules/slickgrid/lib/jquery.event.drag-2.3.0.js", "./node_modules/bootstrap/dist/js/bootstrap.js", "./node_modules/angular-slickgrid/lib/multiple-select/multiple-select.js" Include AngularSlickgridModule in your App Module (app.module.ts) Note Make sure to add the forRoot since it will throw an error in the console when not provided. import { TranslateModule } from '@ngx-translate/core'; import { AngularSlickgridModule } from 'angular-slickgrid'; @NgModule({ declarations: [AppComponent], imports: [ TranslateModule.forRoot(), AngularSlickgridModule.forRoot() ], bootstrap: [AppComponent] }) export class AppModule { } Add to your html/ts page: <div class="container"> <angular-slickgrid gridId="grid1" [columnDefinitions]="columnDefinitions" [gridOptions]="gridOptions" [dataset]="dataset"> </angular-slickgrid> </div> import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { Column, GridOption } from 'angular-slickgrid'; @Component({ selector: 'test', templateUrl: './test.component.html' }) export class TestComponent implements OnInit{ columnDefinitions: Column[] = []; gridOptions: GridOption = {}; dataset: any[] = []; ngOnInit(): void { // grid code this.columnDefinitions = [ { id: 'title', name: 'Title', field: 'title', sortable: true }, { id: 'duration', name: 'Duration (days)', field: 'duration', sortable: true }, { id: '%', name: '% Complete', field: 'percentComplete', sortable: true }, { id: 'start', name: 'Start', field: 'start' }, { id: 'finish', name: 'Finish', field: 'finish' }, { id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', sortable: true } ]; this.gridOptions = { enableAutoResize: true, // true by default enableCellNavigation: true }; // fill the dataset with your data // VERY IMPORTANT, Angular-Slickgrid uses Slickgrid DataView which REQUIREs a unique "id" and it has to be lowercase "id" and be part of the dataset this.dataset = []; // for demo purpose, let's mock a 1000 lines of data for (let i = 0; i < 1000; i++) { const randomYear = 2000 + Math.floor(Math.random() * 10); const randomMonth = Math.floor(Math.random() * 11); const randomDay = Math.floor((Math.random() * 28)); const randomPercent = Math.round(Math.random() * 100); this.dataset[i] = { id: i, // again VERY IMPORTANT to fill the "id" with unique values title: 'Task ' + i, duration: Math.round(Math.random() * 100) + '', percentComplete: randomPercent, start: `${randomMonth}/${randomDay}/${randomYear}`, finish: `${randomMonth}/${randomDay}/${randomYear}`, effortDriven: (i % 5 === 0) }; } } } **Multi-Select** For multi-selects, can use third party ng-select. npm install --save @ng-select/ng-select@2.20.5? Import the NgSelectModule module: import { NgSelectModule } from '@ng-select/ng-select'; import { HttpClientModule } from '@angular/common/http'; import { CommonModule } from '@angular/common'; @NgModule({ declarations: [AppComponent], imports: [NgSelectModule, HttpClientModule, CommonModule], bootstrap: [AppComponent] }) export class AppModule {} In angular.json, add to ‘styles’: ./node_modules/@ng-select/ng-select/themes/material.theme.css Add to your component: Multiselect:<br /> Data:{{people$}}<br/> <ng-select #select [items]="people$ | async" [multiple]="true" bindLabel="name" [(ngModel)]="selectedPeople"> </ng-select> <div class="mt-3"> Selected value: <br /> <ul> <li *ngFor="let item of selectedPeople">{{item.name}}</li> </ul> <button (click)="clearModel()" class="btn btn-secondary btn-sm">Clear model</button> </div> import { Component, OnInit } from '@angular/core'; import { FormControl } from '@angular/forms'; import { Column, GridOption } from 'angular-slickgrid'; import { Observable } from 'rxjs'; import { DataService } from '../services/data.service'; @Component({ selector: 'test', templateUrl: './test.component.html' }) export class TestComponent implements OnInit { // ng multi select constructor(private dataService: DataService) { } people$: Observable<any[]>; selectedPeople = []; clearModel() { this.selectedPeople = []; } ngOnInit(): void { // ng multi select // use any datasource here this.people$ = this.dataService.getPeople(); } **Publish** Site can be published via web deploy publish, or folder publish. Deployment mode either should work but use 'self-contained' if web server is missing the correct .NET Core runtime. Target runtime, choose win-x64 (or other as appropriate) Be sure 'File Publish Options'/'Remove additional files at destination' is checked.
Created By: amos 7/19/2019 11:43:21 AM Updated: 7/19/2019 11:52:14 AM
|
|