标签:angular

以下是与标签 “angular” 相关联的文章

angular5 可用的 WebWorker ThreadPool

  • 完整代码
    • Test Code

       for (let i = 0; i < 10; ++i) {
        const workerTask = new WorkerTask('worker3.js', String(i))
        this.threadPool.addWorkerTask(workerTask)
          .subscribe(
            data => console.log(data),
            err => console.log('err:' + err),
            () => console.log(i + ':finish')
          );
      }
      
    • Web Worker

      import {Observable} from 'rxjs/Observable';
      import 'rxjs/add/observable/timer';
      
      interface DedicatedWorkerGlobalScope extends Window {
        postMessage(data: string): void;
        close(): void;
      }
      
      onmessage = function (e) {
        Observable.timer(1000).subscribe(data => {
          const self = this as DedicatedWorkerGlobalScope;
          for (let i = 0; i < 10; ++i) {
            self.postMessage(e.data + ':' + i);
          }
          self.postMessage('done');
          self.close();
        });
      };    
      
    • ThreadPoolService

      import {Injectable} from '@angular/core';
      import {Observable} from 'rxjs/Observable';
      
      export class WorkerTask {
        public observer;
      
        constructor(public script: string,
                    public startMessage: string) {
        }
      }
      
      class WorkerThread {
        private workerTask: WorkerTask;
      
        constructor(private parentPool: ThreadPoolService) {
        }
      
        public run(workerTask: WorkerTask) {
          this.workerTask = workerTask;
          // create a new web worker
          if (this.workerTask.script != null) {
      
            const worker = new Worker(workerTask.script);
            worker.addEventListener('message', event => this.dummyCallback(event), false);
            worker.postMessage(workerTask.startMessage);
          }
        }
      
        // for now assume we only get a single callback from a worker
        // which also indicates the end of this worker.
        public dummyCallback(event) {
          let done = false;
          // pass to original callback
          if ('data' in event) {
            this.workerTask.observer.next(event.data);
            if (event.data === 'done') {
              done = true;
              this.workerTask.observer.complete();
            }
          } else {
            this.workerTask.observer.error(event);
            done = true;
          }
      
          // we should use a seperate thread to add the worker
          if (done) {
            this.parentPool.freeWorkerThread(this);
          }
        }
      }
      
      @Injectable()
      export class ThreadPoolService {
      
        private taskQueue: WorkerTask[] = [];
        private threadQueue: WorkerThread[] = [];
        private poolSize = 5;
      
        constructor() {
          for (let i = 0; i < this.poolSize; i++) {
            this.threadQueue.push(new WorkerThread(this));
          }
        }
      
        public setSize(size: number) {
          this.poolSize = size;
      
          this.threadQueue = [];
          for (let i = 0; i < size; i++) {
            this.threadQueue.push(new WorkerThread(this));
          }
        }
      
        public addWorkerTask(workerTask: WorkerTask) {
          return Observable.create(observer => {
            workerTask.observer = observer;
      
            if (this.threadQueue.length > 0) {
              // get the worker from the front of the queue
              const workerThread = this.threadQueue.shift();
              workerThread.run(workerTask);
            } else {
              // no free workers,
              this.taskQueue.push(workerTask);
            }
          });
        }
      
        public freeWorkerThread(workerThread: WorkerThread) {
          if (this.taskQueue.length > 0) {
            // don't put back in queue, but execute next task
            const workerTask = this.taskQueue.shift();
            workerThread.run(workerTask);
          } else {
            this.threadQueue.push(workerThread);
          }
        }
      }
      
  • 难点分析
worker.addEventListener('message', event => this.dummyCallback(event), false);

第二个参数,如果写成 this.dummyCallback ,则回调时,this 环境已经变化,代码运行异常。 event => this.dummyCallback(evnet) 是 es5 的语法,用来绑定 this,es6 的语法可以写成 this.dummyCallback.bind(tihs)

angular5 手工注入 HttpClient

  • 手工注入 HttpClient
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {ReflectiveInjector, Type} from '@angular/core';

const injector = ReflectiveInjector.resolveAndCreate(getAnnotations(HttpClientModule)[0].providers);
const httpClient = injector.get(HttpClient);

httpClient.get('www.baidu.com', {responseType: 'text'})
  .subscribe(resp => {
      console.log('resp');
    }
  );

  • 辅助函数
declare let Reflect: any;

function getAnnotations(typeOrFunc: Type<any>): any[] | null {
  // Prefer the direct API.
  if ((<any>typeOrFunc).annotations) {
    let annotations = (<any>typeOrFunc).annotations;
    if (typeof annotations === 'function' && annotations.annotations) {
      annotations = annotations.annotations;
    }
    return annotations;
  }

  // API of tsickle for lowering decorators to properties on the class.
  if ((<any>typeOrFunc).decorators) {
    return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators);
  }

  // API for metadata created by invoking the decorators.
  if (Reflect && Reflect.getOwnMetadata) {
    return Reflect.getOwnMetadata('annotations', typeOrFunc);
  }
  return null;
}

function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] {
  if (!decoratorInvocations) {
    return [];
  }
  return decoratorInvocations.map(decoratorInvocation => {
    const decoratorType = decoratorInvocation.type;
    const annotationCls = decoratorType.annotationCls;
    const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
    return new annotationCls(...annotationArgs);
  });
}

angular5 编译单独 typescript 文件方法

安装 gulp 及相关组件

npm install gulp -g
npm install gulp-typescript gulp-sourcemaps gulp-uglify browserify vinyl-source-stream vinyl-buffer tsify glob gulp-rename event-stream

在根目录下添加 gulpfile.js 文件

gulp = require('gulp');
ts = require('gulp-typescript');
exec = require('child_process').exec;
browserify = require("browserify");
source = require('vinyl-source-stream');
buffer = require('vinyl-buffer');
uglify = require('gulp-uglify');
sourcemaps = require('gulp-sourcemaps');
tsify = require("tsify");
es = require('event-stream');
rename = require('gulp-rename');
glob = require('glob');

gulp.task('ng-build', function (cb) {
  console.log('running ng build...');
  exec('ng build', function (err, stdout, stderr) {
    console.log(stdout);
    console.log(stderr);
    cb(err);
    return true;
  });
});

function tstojs(entry) {
  return browserify({
    basedir: '.',
    debug: true,
    entries: [entry]
  })
    .plugin(tsify)
    .bundle()
    .pipe(source(entry))
    .pipe(rename({
      dirname: './',
      extname: '.js'
    }))
    .pipe(buffer())
    .pipe(sourcemaps.init({
      loadMaps: true
    }))
    .pipe(uglify())
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./dist/'));
}

gulp.task('worker', function (done) {
  console.log('compiling ts to js')
  glob('./src/worker/*.ts', function (err, files) {
    if (err) done(err);

    var tasks = files.map(function (entry) {
      return tstojs(entry);
    });
    es.merge(tasks).on('end', done);
  });
});

gulp.task('watch', function () {
  // gulp.watch('./src/worker/*.ts', ['worker']);
  gulp.watch('./src/worker/*.ts', function (o) {
    return tstojs(o.path);
  });
})

gulp.task('default', [
  'ng-build',
  'worker'
]);

编译方法

  • 全部编译: gulp
  • 编译 worker: gulp worker
  • 监视编译: gulp watch

Angular 实用代码

左侧列表框

<mat-sidenav-container>
  <mat-sidenav #sidenav mode="side" opened="true" position="start">
    <mat-nav-list>
      <mat-list-item *ngFor="let product of productList;" (click)="onSelectProduct(product)">
        <mat-icon matListIcon>{{selectProduct == product ? 'label' : 'label_outline'}}</mat-icon>
        <span matLine>{{product}}</span>
      </mat-list-item>
    </mat-nav-list>
  </mat-sidenav>
  <div class="content">

SnackBar

onDeleteOrder(row: OrderItem) {
  let snackBarRef = this.snackBar.open("Are you sure to delete: " + row.id, "Delete", {
    duration: 3000
  });
  snackBarRef.onAction().subscribe(() => {
    this.regDataDao.deleteOrder(this.selectProduct, row.id).subscribe(data => {
      console.log(data);
      this.dataSource.data = this.dataSource.data.filter(
        orderItem => orderItem.id != row.id);
    });
  });
}

表格中可编辑元素

<mat-cell *matCellDef="let row">
  <div *ngIf="editOrderId == row.id; else else_part">
    <mat-form-field class="order-cell">
      <input matInput placeholder="{{row.order}}" [(ngModel)]="editOrder">
    </mat-form-field>
  </div>
  <ng-template #else_part>{{row.order}}</ng-template>
</mat-cell>

Angular 对话框使用

注入对话框引用

constructor(private dialogRef: MatDialogRef<AddOrderDialogComponent>) {
}

输入框校验

<mat-form-field>
  <input matInput type="email" placeholder="Email" tabindex="2" [ngModel]="email"
         (ngModelChange)="onEmailChange($event)" [formControl]="emailInput">
  <mat-error *ngIf="emailInput.hasError('email')">Error email format.</mat-error>
</mat-form-field>
emailInput = new FormControl();

onEmailChange(email: string) {
  this.email = email;
  if (this.emailAuth == true) {
    if (this.emailInput.hasError('email'))
      this.machine = '';
    else
      this.machine = this.getMachine(this.email);
  }
}

调用对话框

onAddOrder() {
  var dialogRef = this.addOrderDialog.open(AddOrderDialogComponent, {width: '300px'});
  dialogRef.componentInstance.product = this.selectProduct;
  dialogRef.afterClosed().subscribe(order => {
    this.regDataDao.addOrder(this.selectProduct, order).subscribe(data => {
      console.log(data);
      this.dataSource.data.push(data);
      this.dataSource.data = this.dataSource.data;
    });
  });
}

关闭对话框

onAddOrder() {
  var result = {name: this.name, email: this.email, machine: this.machine};
  // console.log(result);
  this.dialogRef.close(result);
}