Data Browser - Viewing Site  Sector 23 Code Bank Logged in as:  Guest  




           


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, selectAngular’ 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