Как получить данные с помощью фабрики AngularJS?

У меня возникла проблема с отображением информации о продукте из базы данных с использованием фабрики AngularJS. По сути, это приложение для корзины покупок, которое я модифицировал для отображения продуктов из базы данных вместо жестко запрограммированного массива.

Вот исходный код основного файла приложения (app.js):

'use strict';

var shop = angular.module('shop', []);

// create a data service that provides a store and a shopping cart that
// will be shared by all views (instead of creating fresh ones for each view)
shop.factory("DataService",['$http', function($http) {
    // create store
    var myStore = new store($http);

    // return data object with store and cart
    return {
       store: myStore
       //cart: myCart ignore for now
    }
}]);

// adding the config on the module
shop.config(function($routeProvider) {
      $routeProvider // angular object, injected dynamically
        .when('/', // we show the store on the root
          {
            controller: 'StoreController',
            templateUrl: 'partials/store.htm'
          })
        .when('/cart',
          {
            controller: 'CartController',
            templateUrl: 'partials/cart.htm'
          })
        .when('/checkout',
          {
            controller: 'CheckoutController',
            templateUrl: 'partials/checkout.htm'
          })
       .when('/invoice',
          {
            controller: 'InvoiceController',
            templateUrl: 'partials/invoice.htm'
          })
       .otherwise({ redirectTo: '/' }); // store
    });

var controllers = {};
controllers.StoreController = function($scope, $routeParams, DataService) {
  $scope.store = DataService.store;
  console.log($scope.store);
  //$scope.cart = DataService.cart;
}

Исходный код магазина (store.js), где я получаю данные:

function store($http) {
  this.products = [];
  this.url = 'php/db.php';
  this.fields = [
    'product_id',
    'product_name', 
    'product_description', 
    'product_price'
  ];
  this.products = this.getProducts($http);
}

store.prototype.getProducts = function($http) {
  $http.post(this.url, { "action" : 'products', "fields" : this.fields })
    .success(function(data, status) {
      //$scope.result = data; // Show result from server in our <pre></pre> element
      //return data;
      this.products = data;
    })
    .error(function(data, status) {
      //return data || "Request failed";
      //this.status = status;        
      this.products = [];
  }); 
}

store.prototype.getProduct = function (sku) {
  for (var i = 0; i < this.products.length; i++) {
    if (this.products[i].sku == sku)
      return this.products[i];
  }
  return null;
}

Может ли кто-нибудь сказать мне, что я делаю неправильно здесь?

  • Почему я не могу установить переменную this.product в результат базы данных?
  • Я также хотел бы расширить класс продуктов дополнительными функциями для сохранения элементов в базе данных, как мне это сделать?

Любые советы очень ценятся.

С уважением

ОБНОВЛЕНИЕ

Я добавил код app.js ниже. У меня возникла проблема с контроллером (StoreController) при доступе к данным из класса хранилища (store.js). Он по-прежнему показывает пустой массив. Я изменил свой код, как было предложено m.e.conroy.

app.js

'use strict';

var shop = angular.module('shop', []);


shop.factory("DataService",['$http', '$q', function($http, $q) {
    // create store
    var myStore = new store($http, $q);
    return {
       store: myStore      
    }
}]);


// adding the config on the module
shop.config(function($routeProvider) {
      $routeProvider // angular object, injected dynamically
        .when('/', // we show the store on the root
          {
            controller: 'StoreController',
            templateUrl: 'partials/store.htm'
          })
        .when('/cart',
          {
            controller: 'CartController',
            templateUrl: 'partials/cart.htm'
          })
        .when('/checkout',
          {
            controller: 'CheckoutController',
            templateUrl: 'partials/checkout.htm'
          })
       .when('/invoice',
          {
            controller: 'InvoiceController',
            templateUrl: 'partials/invoice.htm'
          })
       .otherwise({ redirectTo: '/' }); // store
    });

var controllers = {};
controllers.StoreController = function($scope, $http, $routeParams, DataService) {
  $scope.store = DataService.store;              
}

shop.controller(controllers); 

person Chesneycar    schedule 24.10.2013    source источник
comment
DataService.store возвращает обещание, поэтому вам нужно решить, чтобы поймать значение. И кажется, что ваша хранимая функция не возвращает объект результата... вам нужно вернуть этот объект. Можете ли вы создать пример плунжера с полной реализацией фабрики хранилища?   -  person Deividi Cavarzan    schedule 24.10.2013
comment
Посмотрите на этот хороший пример приложения angularjs github.com/andreev-artem/angular_experiments /tree/master/ и здесь jsfiddle.net/u5gV2 для простого кэша памяти.   -  person Peter Gerasimenko    schedule 24.10.2013
comment
возвращаемые данные не определены. в коде я установил переменную this.products на ту, которая возвращается в обработчике успеха.   -  person Chesneycar    schedule 24.10.2013
comment
Вам не нужно устанавливать this.products = this.getProducts($http), если вы собираетесь установить this.products в функциях успеха или ошибки $http.post. Вы даже ничего не возвращаете из getProducts, поэтому this.products устанавливается в определение функции.   -  person m.e.conroy    schedule 24.10.2013


Ответы (1)


function store($http) {
    this.products = [];
    this.url = 'php/db.php';
    this.fields = ['product_id', 'product_name', 'product_description', 'product_price'];
    this.products = this.getProducts($http);
}

store.prototype.getProducts = function ($http) {
    return $http.post(this.url, {
        "action": 'products',
        "fields": this.fields
    })
    .success(function (data, status) {
        return data;
    })
    .error(function (data, status) { 
        return [];
    });
}

Когда вы возвращаете $http.post, вы возвращаете promise, которое он создает, поэтому this.products будет содержать обещание $http. Когда вызов возвращается с сервера, обещание разрешается функциями success или error, возвращающими данные в этих функциях, устанавливает переменную this.products в то, что возвращается.

В этом случае this.products = [] сразу же заменяется обещанием из $http.. Если вы попытаетесь получить доступ к этим данным в своем приложении до того, как произойдет разрешение, вы вернете содержащееся в нем обещание, которое может вызвать проблемы, если вы попытаетесь использовать его в других функциях. как если бы он содержал нужный вам массив. Вы можете использовать $q.when, чтобы «подождать» обещание разрешить, а затем назначить возвращенные данные, поэтому, если вы попытаетесь использовать this.products в другом месте до этого, он все равно будет содержать пустой массив, и, таким образом, код, подобный this.products.length, все равно будет работать, а не выдавать ошибку. . Итак, вы можете сделать следующее:

function store($http,$q) {
    this.products = [];
    this.url = 'php/db.php';
    this.fields = ['product_id', 'product_name', 'product_description', 'product_price'];
    $q.when(this.getProducts($http)).then(function(data){ this.products = data; });
}

Если вы решите пойти по этому пути, просто обратите внимание, что вам нужно будет внедрить $q в свой сервис, а затем передать его через оператора new во время создания класса. Это разрешит любую ситуацию с гонками, которая может возникнуть в вашем контроллере.

Конечно, вы также можете использовать resolve, предоставленный для метода .when метода $routeProvider, для разрешения и зависимостей контроллера до того, как контроллер возьмет на себя «управление».

person m.e.conroy    schedule 24.10.2013
comment
Спасибо за ваш ответ, я изменил свой код и обновил вопрос с помощью своих контроллеров. Просто нужно немного больше направления. Спасибо! - person Chesneycar; 24.10.2013
comment
Вы также изменили свой store.js, чтобы добавить $q? - person m.e.conroy; 25.10.2013
comment
Я провел некоторое тестирование, и хотя в моем примере this.getProducts для хранилища вызывается и возвращает правильное значение в операторе $q, значение в $scope.store в контроллере никогда не устанавливается. У меня есть ощущение, что сделать это таким образом во время создания объекта не получится. Я предлагаю пойти по чистому маршруту Angular и использовать фабричный сервис в качестве хранилища объектов (сервиса). - person m.e.conroy; 25.10.2013
comment
Спасибо! Я взгляну. Я ценю вашу помощь. - person Chesneycar; 25.10.2013
comment
Спасибо за руководство и совет, отметив вопрос как ответ. - person Chesneycar; 28.10.2013
comment
@Chesney, рад, что смог помочь некоторым, возможно, это не так, как вы хотели закодировать, но я рад, что смог хотя бы дать вам некоторое представление. Надеюсь, ваш проект пойдет хорошо, и надеюсь, что вы продолжите использовать Angular, как только вы к нему привыкнете, это действительно сэкономит время. - person m.e.conroy; 28.10.2013
comment
Спасибо @m.e.conroy, я очень ценю вашу помощь. Я сделал несколько модификаций, и теперь все работает как в Angular ;) Я опубликую проект на github, когда закончу. - person Chesneycar; 29.10.2013
comment
Привет, @m-e-conroy, можешь ли ты помочь с другим вопросом AngularJS? У меня проблема с фильтрами. Я разместил вопрос здесь - stackoverflow.com/questions/19948280/ - person Chesneycar; 13.11.2013