2015-10-10 4 views
6

Ich versuche, einen benutzerdefinierten Filter von einem Angular-Controller aufzurufen, aber ich erhalte den Fehler: 'Kann keinen Ausdruck aufrufen, dessen Typ fehlt eine Signatur ".Der Versuch, benutzerdefinierte Filter aufzurufen, führt zu einem Fehler TS2349: Kann keinen Ausdruck aufrufen, dessen Typ keine Anrufsignatur enthält.

Ich habe es so bei dem letzten Projekt, an dem ich gearbeitet habe, implementiert, so dass ich nicht weiß, was falsch ist.

Der Filter enthält zu diesem Zeitpunkt keine Logik, da ich ihn zuerst kompilieren muss. Hier

ist der Filter:

/// <reference path="../../typings/reference.ts" /> 

module app { 
'use strict'; 

/** 
* Filter models 
*/ 
export class ModelFilter { 
    public static Factory() { 
     return function(input: string) { 
      console.log(input); 
      return input; 
     } 
    } 
} 

angular.module('app') 
    .filter('modelFilter', [ModelFilter.Factory]); 
} 

Und die Steuerung, wo es heisst:

/// <reference path="../../typings/reference.ts" /> 

module app { 
'use strict'; 

interface ISearchController { 
    vehicles: IVehicles; 
    models: any; 
    setVehicles(): void; 
    updateModels(make: string): void; 
} 

class SearchController implements ISearchController { 

    static $inject = [ 
     'VehicleMakeService', 
     'VehicleModelService', 
     '$filter' 
    ]; 
    constructor(private vehicleMakeService: VehicleMakeService, 
       private vehicleModelService: VehicleModelService, 
       private $filter: ng.IFilterService, 
       public vehicles: IVehicles, 
       public models: any) { 

     this.setVehicles(); 
    } 

    setVehicles(): void { 
     this.vehicleMakeService.getVehicles().then((data) => { 
      this.vehicles = data; 
     }); 
    } 

    updateModels(make: string): void { 

     var test = this.$filter('modelFilter')(make); // Error here 
    } 
} 
angular.module('app').controller('SearchController', SearchController); 
} 

reference.ts:

/// <reference path="./tsd.d.ts" /> 

//grunt-start 
/// <reference path="../app/app.config.ts" /> 
/// <reference path="../app/app.module.ts" /> 
/// <reference path="../app/app.route.ts" /> 
/// <reference path="../app/home/home.controller.ts" /> 
/// <reference path="../app/home/home.route.ts" /> 
/// <reference path="../app/models/vehicles.model.ts" /> 
/// <reference path="../app/results/results.controller.ts" /> 
/// <reference path="../app/results/results.route.ts" /> 
/// <reference path="../app/services/cars.service.ts" /> 
/// <reference path="../app/services/vehicles.make.service.ts" /> 
/// <reference path="../app/services/vehicles.models.service.ts" /> 
/// <reference path="../app/templates/search.controller.ts" /> 
/// <reference path="../app/templates/search.filter.ts" /> 
//grunt-end 

tsd.d.ts:

/// <reference path="angularjs/angular.d.ts" /> 
/// <reference path="jquery/jquery.d.ts" /> 
/// <reference path="angular-ui-router/angular-ui-router.d.ts" /> 
/// <reference path="angularjs/angular-resource.d.ts" /> 

Antwort

10

Modified Arbeitsbeispiel:

/// <reference path="typings/angularjs/angular.d.ts" /> 

module app { 

    // ADDED <--- MODIFIED! 
    export interface MyModelFilter extends ng.IFilterService { 
     (name: 'modelFilter'): (input: string) => string; 
    } 

    /** 
    * Filter models 
    */ 
    export class ModelFilter { 
     public static Factory() { 
      return function(input: string) { 
       console.log(input); 
       return input; 
      } 
     } 
    } 

    angular.module('app') 
     .filter('modelFilter', [ModelFilter.Factory]); 
} 

module app { 

    class SearchController { 
     constructor(private $filter: MyModelFilter) { // <--- MODIFIED! 
     } 

     updateModels(make: string): void { 
      var test = this.$filter('modelFilter')(make); 
     } 
    } 
    angular.module('app').controller('SearchController', SearchController); 
} 

Das Problem ist, dass Typoskript folgende definition verwendet:

/** 
* $filter - $filterProvider - service in module ng 
* 
* Filters are used for formatting data displayed to the user. 
* 
* see https://docs.angularjs.org/api/ng/service/$filter 
*/ 
interface IFilterService { 
    (name: 'filter'): IFilterFilter; 
    (name: 'currency'): IFilterCurrency; 
    (name: 'number'): IFilterNumber; 
    (name: 'date'): IFilterDate; 
    (name: 'json'): IFilterJson; 
    (name: 'lowercase'): IFilterLowercase; 
    (name: 'uppercase'): IFilterUppercase; 
    (name: 'limitTo'): IFilterLimitTo; 
    (name: 'orderBy'): IFilterOrderBy; 
    /** 
    * Usage: 
    * $filter(name); 
    * 
    * @param name Name of the filter function to retrieve 
    */ 
    <T>(name: string): T; 
} 

für this.$filter('modelFilter'). Dies bedeutet, dass die letzte Regel (d. H. <T>(name: string): T;) verwendet wird. Folglich ist this.$filter('modelFilter') vom Typ ng.IFilterService und TypeScript weiß nichts über Ihre ModelFilter.

Sie können das Problem lösen, indem Sie eine neue Schnittstelle hinzufügen, wie in der ersten Codeliste gezeigt.

Sie sagten, dass der ursprüngliche Code in einem anderen Projekt von Ihnen funktioniert hat, aber es scheint mir sehr unwahrscheinlich, es sei denn, reference.ts wurde irgendwie geändert.

+0

Ich habe Ihre Lösung versucht, aber ich bekomme genau den gleichen Fehler. FYI, Referenz .ts wird mit grunt-ts erstellt, die einen Verweis auf tsd.d.ts enthält, der den Verweis auf angular.d.ts enthält, also enthält reference.ts grundsätzlich einen Verweis auf alle ts-Dateien in der Anwendung die eindeutig typisierten Dateien. Ich habe meine Frage aktualisiert, um dies zu zeigen. – AngularBoy

+0

Können Sie Ihren modifizierten Code in einem Pastebin posten? –

+0

Ich verwende TypeScript 1.6.2. Wie auch immer, du kannst Code von hier https://pastee.org/5hfp auf http://www.typescriptlang.org/Playground setzen, um zu sehen, dass es funktioniert. –

0

Ich wollte nur ein ähnliches Beispiel mit der Moment-Bibliothek teilen, um Daten entweder in einem Controller oder im Frontend zu formatieren.

export interface IMomentFilter extends ng.IFilterService { 
    (name: 'momentFilter'): (dateString: string, format: string) => string; 
} 

export class MomentFilter { 
    public static Factory() { 
     return function (dateString: string, format: string) { 
      return moment(dateString).format(format); 
     } 
    } 
} 

So kann es in der Steuerung ein Datum unter Verwendung der Ag-grid cellrenderer Formatierung verwendet werden:

var columnDefs = [ 
{ 
    headerName: "Reported Date", 
    field: "reportedDate", 
    cellRenderer: function (params) 
    { 
     return $filter('momentFilter')(params.value, "MM/DD/YYYY"); 
    } 
}]; 

Dieses ist, wie es auf dem Front-End verwendet werden:

<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">Created Date: 
    <label class="field"> 
    <label class="field">{{vm.model.reportedDate| momentFilter:'MM/DD/YYYY' }}</label> 
    </label> 
</div> 

Ich hoffe, das hilft. Vielen Dank für den ursprünglichen Beitrag. Ich habe mich wirklich am Kopf kratzt, um mit der IFilterService-Schnittstelle die richtige Syntax zu bekommen.

1

Wenn Sie die letzte Zeile des IFilterService sehen, gibt es einen generischen Typ für benutzerdefinierte Filter.

interface IFilterService { 
    (name: 'filter'): IFilterFilter; 
    (name: 'currency'): IFilterCurrency; 
    (name: 'number'): IFilterNumber; 
    (name: 'date'): IFilterDate; 
    (name: 'json'): IFilterJson; 
    (name: 'lowercase'): IFilterLowercase; 
    (name: 'uppercase'): IFilterUppercase; 
    (name: 'limitTo'): IFilterLimitTo; 
    (name: 'orderBy'): IFilterOrderBy; 
    /** 
    * Usage: 
    * $filter(name); 
    * 
    * @param name Name of the filter function to retrieve 
    */ 
    <T>(name: string): T; 
} 

Wie der Fehler schon sagt, haben Ihre benutzerdefinierten Filter keinen Anruf Signatur.So können Sie eine Schnittstelle für Ihren Filter erstellen, die einen Anruf Signatur enthält:

export interface MyModelFilter { 
    (input: string): string; 
} 

Und dann, wenn Sie Ihren Filter aufrufen können Sie die IFilterService generischen Typ verwenden, um Ihren Anruf Signatur zu Ihren benutzerdefinierten Filter-Attribut

updateModels(make: string): void { 
    var test = this.$filter<MyModelFilter>('modelFilter')(make); 
}