Angular2 HTTP-запрос

Привет, я пытаюсь сделать запрос на получение, используя модуль HTTP в Angular2.

В Typescript (1.5) все компилируется нормально, но Chrome показывает в консоли следующую ошибку:

EXCEPTION: Error during instantiation of EntryList!. ORIGINAL
EXCEPTION: TypeError: Cannot read property 'merge' of undefined
ORIGINAL STACKTRACE: TypeError: Cannot read property 'merge' of undefined
at mergeOptions (angular2.dev.js:27991)  
at execute.Http.get (angular2.dev.js:28052)  
at EntryService.getEntries (services.js:17)
at new EntryList (entry-list.js:20)

Услуги.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Http, Observable } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;
    private _http : Http;

    constructor() {     
        this._entries = ["test1", "test2", "test3"];
        this._http = new Http;      
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {
        console.log(this._http);
        return this._http.get('http://localhost:53338/api/decisions')       
            .toRx()
            .map((response) => { 
                response.json()
            });     
    }
}

запись-list.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
/// <reference path="../modules/services.ts" />

import { Component, View, NgFor } from "angular2/angular2"
import { EntryService } from "modules/services"

@Component({
    selector: 'entry-list'  
})
@View({
    directives: [ NgFor ],
    templateUrl: "../views/entry-list.html" 
})
export class EntryList {
    entries: Array<string>; 

    constructor(public service: EntryService) {     
        this.entries = this.service.Entries;
        this.service.getEntries().subscribe((response) => {     
            console.log(response);
        }); 
    }
}

app.ts

/// <reference path="typings/angular2/angular2.d.ts" />
/// <reference path="components/entry-list.ts" />
/// <reference path="modules/services.ts" />

import { Component, View, bootstrap, NgFor } from "angular2/angular2"
import { EntryList } from "components/entry-list"
import { EntryService } from "modules/services"

@Component({
    selector : "app",
    bindings: [ EntryService ]  
})
@View({
    directives: [ EntryList ],
    templateUrl: "views/app.html"   
})
class App { 
    constructor() {
        console.log('hit');
    }
}

bootstrap(App);

index.html

<html>
    <head>
        <title>SCM</title>
        <script src="https://github.jspm.io/jmcriffey/[email protected]/traceur-runtime.js"></script>
        <script src="https://jspm.io/[email protected]"></script>      
        <script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js"></script>
    </head>
    <body>
        <app></app>
        <script>System.import('app')</script>
    </body>
</html> 

Я просмотрел документацию по API на сайте angular.io, но не понял, что не так.

ОБНОВИТЬ

Услуги.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Http, Observable, httpInjectables } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;    

    constructor(private http: Http) {       
        this._entries = ["test1", "test2", "test3"];            
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {
        console.log(this.http);
        return this.http.get('http://localhost:53338/api/decisions')        
            .toRx()
            .map((response) => { 
                response.json()
            });     
    }
}

запись-list.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
/// <reference path="../modules/services.ts" />

import { Component, View, NgFor, Http, httpInjectables } from "angular2/angular2"
import { EntryService } from "modules/services"

@Component({
    selector: 'entry-list',
    bindings : [ Http, httpInjectables ]
})
@View({
    directives: [ NgFor ],
    templateUrl: "../views/entry-list.html" 
})
export class EntryList {
    entries: Array<string>; 

    constructor(public service: EntryService) {     
        this.entries = this.service.Entries;
        this.service.getEntries().subscribe((response) => {     
            console.log(response);
        }); 
    }
}

app.ts

/// <reference path="typings/angular2/angular2.d.ts" />
/// <reference path="components/entry-list.ts" />
/// <reference path="modules/services.ts" />

import { Component, View, bootstrap, NgFor, Http, httpInjectables } from "angular2/angular2"
import { EntryList } from "components/entry-list"
import { EntryService } from "modules/services"

@Component({
    selector : "app",
    bindings: [ EntryService, Http, httpInjectables ]   
})
@View({
    directives: [ EntryList ],
    templateUrl: "views/app.html"   
})
class App { 
    constructor() {
        console.log('hit');
    }
}

bootstrap(App);

Без изменений в index.html

Изменить: мой файл services.ts изменяется, чтобы это заработало:

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Injector, Http, httpInjectables } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;    
    private http: Http;

    constructor() {     
        this._entries = ["test1", "test2", "test3"];        

        var injector = Injector.resolveAndCreate([
                httpInjectables,
                Http
            ]);
        this.http = injector.get(Http);                 
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {       
        return this.http.get('http://localhost:53338/api/decisions')        
            .toRx()
            .map(response => response.json());      
    }
}

person Werner Swart    schedule 19.08.2015    source источник


Ответы (2)


Вы не должны создавать экземпляр Http самостоятельно, вместо этого введите его:

public constructor(http : Http) {
    this.http = http;
}

В документации сказано:

Http доступен как внедряемый класс с методами для выполнения HTTP-запросов.

Поэтому я не уверен, каков будет результат, если вы создадите экземпляр самостоятельно, но почему-то ему не удается выполнить запрос на получение из-за некоторых внутренних элементов, которые не определены.

Изменить: добавление дополнительных источников.

@Injectable()
export class Http {
    constructor(protected _backend: ConnectionBackend, protected _defaultOptions: RequestOptions) {}

    /**
     * Performs a request with `get` http method.
     */
    get(url: string, options?: RequestOptionsArgs): EventEmitter {
        return httpRequest(this._backend, new Request(mergeOptions(this._defaultOptions, options, RequestMethods.GET, url)));
  }
}

Здесь я добавил небольшую часть класса Http из репозитория github. Вы можете видеть, что _backend и _defaultOptions заданы в конструкторе, который вы не указали, и метод get() создаст параметры для запроса на основе параметра options и _defaultOptions, заданных в конструкторе, поскольку вы не предоставляете ни одного из них. , я считаю, что он падает в вызове mergeOptions, который вы можете найти здесь:

function mergeOptions(defaultOpts, providedOpts, method, url): RequestOptions {
  var newOptions = defaultOpts;
  if (isPresent(providedOpts)) {
    // Hack so Dart can used named parameters
    newOptions = newOptions.merge(new RequestOptions({
      method: providedOpts.method,
      url: providedOpts.url,
      search: providedOpts.search,
      headers: providedOpts.headers,
      body: providedOpts.body,
      mode: providedOpts.mode,
      credentials: providedOpts.credentials,
      cache: providedOpts.cache
    }));
  }
  if (isPresent(method)) {
    return newOptions.merge(new RequestOptions({method: method, url: url}));
  } else {
    return newOptions.merge(new RequestOptions({url: url}));
  }
}

В последнем if/else функции. Для получения дополнительной информации исходный файл находится здесь.

person Arnaud Boeglin    schedule 19.08.2015
comment
Спасибо за ответ. Первое, что я хочу попробовать, это внедрить класс Http в мой класс EntryService. Как вы можете видеть из приведенного выше кода, есть 3 отдельных файла, я знаю, что использование свойства привязки в аннотации компонента сделает этот объект доступным для инъекции через приложение, я попытался указать там класс Http для инъекции, но я получаю ошибки в моем конструкторе EntryService, если я попытаюсь внедрить это. Знаете ли вы, как сделать объект Http доступным для внедрения для EntryService? - person Werner Swart; 19.08.2015
comment
На самом деле я просто изменил код. И ошибок нет ни для машинописного компилятора, ни внутри хрома, но приложение не работает. - person Werner Swart; 19.08.2015
comment
вы можете импортировать httpInjectables из angular2 и передать его непосредственно вашему вызову начальной загрузки, это метод, который я успешно использовал сам, и который на данный момент кажется классическим способом. Можете ли вы обновить свой код, чтобы отразить последние изменения? - person Arnaud Boeglin; 19.08.2015
comment
Я обновил код, я также безуспешно пытался передать объект Http в вызов начальной загрузки (хотя и не в приведенном выше коде). - person Werner Swart; 20.08.2015
comment
Просто укажите httpInjectables в начальной загрузке и включите в свой сервис только Http. И тогда вам больше не нужно привязывать его к вашему инжектору приложений. Не могли бы вы попытаться настроить plnkr и воспроизвести проблему? - person Arnaud Boeglin; 20.08.2015
comment
Привет, извините, что так долго не отвечал, я потратил некоторое время на чтение файлов Http.ts и какие-либо ресурсы, которые я мог найти, чтобы понять больше, и, наконец, я лучше понял ваш ответ. Я до сих пор не знаю, как вводить переменные в дочерние классы дочерних компонентов, но то, что мне удалось сделать в моем файле services.ts, - это создать экземпляр инжектора, а затем выполнить var http = инжектор.get(Http) и что работал. Код был следующим: var инжектор = Injector.resolveAndCreate([ httpInjectables, Http ]); this.http = инжектор.get(Http); Спасибо за помощь!! - person Werner Swart; 22.08.2015
comment
@Amaud Можете ли вы показать пример того, как это сделать в начальной загрузке? - person Serj Sagan; 02.01.2016

Вы действительно хотите использовать другую библиотеку только для запросов CRUD/HTTP? **

Тогда я бы настоятельно рекомендовал es6 де-факто. На мой взгляд, на данный момент это не только проще, чем angular2/http, но и стандартно сейчас и в будущих версиях.

** Это работает из коробки для сафари, хрома, ie-edge и Firefox.

person user2379441    schedule 14.10.2015
comment
Пример был бы полезен для поддержки вашего дела - person Serj Sagan; 02.01.2016