2016-03-03 99 views
7

我有一個基本的服務,看起來像這樣:AngularJS服務繼承問題

.service('BaseImageService', ['$q', 'ApiHandler', 'UploadService', function ($q, api, uploadService) { 

    // Get our api path 
    var apiPath = 'logos'; 

    // Creates our logo 
    var _createLogo = function (model) { 

     // Handle our uploads 
     return _handleUploads(model).then(function() { 

      // Create our logo 
      return api.post(apiPath, model); 
     }); 
    }; 

    // Edit our logo 
    var _editLogo = function (model) { 

     // Handle our uploads 
     return _handleUploads(model).then(function() { 

      // Create our logo 
      return api.put(apiPath, model); 
     }); 
    }; 

    // Handles our files 
    var _handleUploads = function (model) { 

     // Create a promises array 
     var promises = []; 

     // Get our file 
     var file = model.file, 
      old = model.old; 

     // If we have a file 
     if (file) { 

      // Try to upload the file 
      promises.push(uploadService.upload(model.file).then(function (response) { 

       // Update our model 
       model.path = response.path; 
       model.thumbnail = response.thumbnail; 
      })); 

      // If we have an old model 
      if (old) { 

       // Delete both our files 
       promises.push(uploadService.delete(old.path)); 
       promises.push(uploadService.delete(old.thumbnail)); 
      } 
     } 

     // After all promises have completed 
     return $q.all(promises); 
    }; 

    // Create our service 
    var service = { 

     // Update our api path 
     updateApiPath: function (path) { 

      // Set the api path 
      apiPath = path; 
     }, 

     // Gets a list of logos 
     list: function (t) { 

      if (t) { 
       console.log(apiPath); 
      } 

      // Get our logo 
      return api.get(apiPath); 
     }, 

     // Get a single logo 
     get: function (id) { 

      // Get our logo 
      return api.get(apiPath, { id: id }); 
     }, 

     // Create our logo 
     save: function (model) { 

      // If we are editing 
      if (model.id) { 

       // Edit our logo 
       return _editLogo(model); 

       // If we are creating 
      } else { 

       // Create our logo 
       return _createLogo(model); 
      } 
     }, 

     // Deletes our logo 
     delete: function (id) { 

      // Delete our logo 
      return api.delete(apiPath, { id: id }); 
     }, 

     // Prepare for editing 
     prepareForEditing: function (model) { 

      // Create our old object 
      model.old = { 
       path: model.path, 
       thumbnail: model.thumbnail 
      }; 
     } 
    }; 

    // Return our service 
    return service; 
}]) 

,然後我有幾個服務,「繼承」這個服務,像這樣:

.service('ImageService', ['BaseImageService', function (baseService) { 

    // Get our api path 
    var apiPath = 'images'; 

    // Update the apiPath 
    baseService.updateApiPath(apiPath); 

    // Return our service 
    return baseService; 
}]) 

.service('LogoService', ['BaseImageService', function (baseService) { 

    // Get our api path 
    var apiPath = 'logos'; 

    // Update the apiPath 
    baseService.updateApiPath(apiPath); 

    // Return our service 
    return baseService; 
}]) 

.service('PlayerTextService', ['BaseImageService', function (baseService) { 

    // Get our api path 
    var apiPath = 'playerText'; 

    // Update the apiPath 
    baseService.updateApiPath(apiPath); 

    // Return our service 
    return baseService; 
}]) 

我想這工作正常。但我有這個頁面依次調用所有3個服務(ImageService,LogoService和PlayerTextService)。在頁面的第一個視圖中,一切都很好,如果我導航離開,然後回來,圖像服務實際上會從播放器文本服務中拉回東西。現在我知道這是因爲服務是單身人士,但我不知道如何解決我的問題。

任何人都可以幫我一把嗎?


我添加了一個codepen與嘗試的解決方案:

http://codepen.io/r3plica/pen/ONVBJO


嘗試2

http://codepen.io/r3plica/pen/jqPeMQ?editors=1010

+0

你正在創建工廠不'service'和每一個服務不應該返回baseService。不太清楚你想要做什麼 – charlietfl

+0

將base轉換爲實際的'service',它是一個構造函數,它使用'this'用於成員...然後從其他工廠返回'new baseService' – charlietfl

+0

您可以修改codepen作爲示例? – r3plica

回答

2

很多亂搞的後;我終於找到了解決辦法adapting this bit of code

我的基本服務是這樣的:

.factory('BaseImageService', ['$q', 'ApiHandler', 'UploadService', 'vectorExtensions', function ($q, api, uploadService, vectorExtensions) { 

    // Creates our logo 
    var _createLogo = function (model) { 

     // Handle our uploads 
     return _handleUploads(model).then(function() { 

      // Create our logo 
      return api.post(BaseImageService.apiPath, model); 
     }); 
    }; 

    // Edit our logo 
    var _editLogo = function (model) { 

     // Handle our uploads 
     return _handleUploads(model).then(function() { 

      // Create our logo 
      return api.put(BaseImageService.apiPath, model); 
     }); 
    }; 

    // Handles our files 
    var _handleUploads = function (model) { 

     // Create a promises array 
     var promises = []; 

     // Get our file 
     var file = model.file, 
      old = model.old; 

     // If we have a file 
     if (file) { 

      // Try to upload the file 
      promises.push(uploadService.upload(model.file).then(function (response) { 

       // Update our model 
       model.path = response.path; 
       model.thumbnail = response.thumbnail; 
       model.fileName = response.fileName; 
      })); 

      // If we have an old model 
      if (old) { 

       // Delete both our files 
       promises.push(uploadService.delete(old.path)); 
       promises.push(uploadService.delete(old.thumbnail)); 
      } 
     } 

     // After all promises have completed 
     return $q.all(promises); 
    }; 

    // Addes a property to the image array to state if they are vector images or not 
    var _addVectorProperties = function (images) { 

     // Loop through our images 
     for (var i = 0; i < images.length; i++) { 

      // Get our current image 
      var image = _addVectorProperty(images[i]); 
     } 

     // Return our images 
     return images; 
    }; 

    // Adds a property to the image to state if it is vector or not 
    var _addVectorProperty = function (image) { 

     // Vector flag 
     var vector = false; 

     // Get our file extension 
     var parts = image.path.split('.'); 

     // If we have any parts 
     if (parts.length) { 

      // Get our last part 
      var ext = parts[parts.length - 1], 
       index = vectorExtensions.indexOf(ext); 

      // If our extension exists in our vector array 
      if (index > -1) { 

       // Change our vector property 
       vector = true; 
      } 
     } 

     // Update our image with the new property 
     image.vector = vector; 

     // Return our image 
     return image; 
    }; 

    // Create our service 
    var BaseImageService = function (path) { 

     // Set our apiPath 
     this.apiPath = path; 

     // Update our api path 
     this.updateApiPath = function (path) { 

      // Set the api path 
      apiPath = path; 
     }; 

     // Gets a list of logos 
     this.list = function() { 

      // Get our logo 
      return api.get(this.apiPath).then(_addVectorProperties); 
     }; 

     // Get a single logo 
     this.get = function (id) { 

      // Get our logo 
      return api.get(this.apiPath, { id: id }).then(_addVectorProperty); 
     }; 

     // Create our logo 
     this.save = function (model) { 

      // If we are editing 
      if (model.id) { 

       // Edit our logo 
       return _editLogo(model); 

       // If we are creating 
      } else { 

       // Create our logo 
       return _createLogo(model); 
      } 
     }; 

     // Deletes our logo 
     this.delete = function (id) { 

      // Delete our logo 
      return api.delete(this.apiPath, { id: id }); 
     }; 

     // Set our active image 
     this.setActive = function (images, image) { 

      // Loop through our images 
      for (var i = 0; i < images.length; i++) { 

       // Get our current image 
       var current = images[i]; 

       // Set whether we are active or not 
       current.active = image.id === current.id ? true : false; 
      } 
     }; 

     // Prepare for editing 
     this.prepareForEditing = function (model) { 

      // Create our old object 
      model.old = { 
       path: model.path, 
       thumbnail: model.thumbnail 
      }; 
     }; 
    }; 

    // Return our service 
    return BaseImageService; 
}]) 

和兒童服務是這樣的:

.service('ImageService', ['BaseImageService', function (baseService) { 

    // Create our base service 
    var child = new baseService('images'); 

    // Return our new service 
    return child; 
}]) 

.service('LogoService', ['BaseImageService', function (baseService) { 

    // Create our base service 
    var child = new baseService('logos'); 

    // Return our new service 
    return child; 
}]) 

.service('PlayerTextService', ['BaseImageService', function (baseService) { 

    // Create our base service 
    var child = new baseService('playerText'); 

    // Return our new service 
    return child; 
}]) 

這工作正常。

+0

請注意,在這個版本中,你以某種方式繞過依賴注入機制,難以測試你的控制器,因爲你在測試執行期間不再能夠注入一些修改過的「子服務」......(只有當你模擬整個父服務時) –

2

你試過不工作的解決方案因爲BaseService是一個單身人士。因此,您將完全相同的實例注入到所有三個服務註冊函數中,並且它們都配置相同的對象。所以基本上最後一個贏了。

看起來像你想擁有不同配置的單獨服務。這是供應商的用途。它們允許構建服務實例的兩個步驟。請參閱有關該主題的偉大的答案#1:

AngularJS: Service vs provider vs factory

僅供參考,Restangular是需要達到你想要的一模一樣的庫。您可以使用此爲藍本,看看Restangular如何處理這個要求:這些概念是基於AngularJS 1

https://github.com/mgonto/restangular#how-to-create-a-restangular-service-with-a-different-configuration-from-the-global-one

請注意,你需要以不同的方式處理這個問題的時候,你以後要使用AngularJS 2上。

0

是的,它是因爲它是單身人士而被追加的。如果你想這樣做,你必須執行繼承。

這裏是我使用,並追加到角代碼:

angular.baseResourceServiceMaker = function(service){ 
    return ['$injector', '$resource', 'TypeService', '$http', '_', 'BackEndpoint', 
     function($injector, $resource,TypeService, $http, _, BackEndpoint){ 

    //skipping not interesting code 
    // sample fields to inherits 
    this.sample = "test"; 
    this.sampleFN = function(){[...]} 
    // THE line that does the magic 
    $injector.invoke(service, this); 
} 

現在使用

.service('MyService',angular.baseResourceServiceMaker(['$http', function($http){ 
    // overriding fields 
    this.sample="inherits"; 
this.sampleFN = function(){[...]} 
}])); 

所以基本上我們有什麼在這裏的時間?表示通用特定服務的函數baseResourceServiceMaker。調用我們想要實例化的服務的$注入器,並將範圍設置爲通用服務,因此子類上的這一點將綁定到與泛型類相同的引用。通用服務將被多次實例化,不會有任何爭議。

我個人使用此代碼爲angular的資源模塊定義一些具有自定義序列化器/反序列化器的基本方法,而不是處理日期和其他一些東西。在你的情況下,baseResourceServiceMaker將作爲你的baseImageService以$ injector.invoke(service,this)結尾。

編輯:找到的東西可能更清潔的鏈接:AngularJS service inheritance

+0

我嘗試了你提供的鏈接中的所有鏈接,但是他們都沒有工作。我會給你一個嘗試,讓你知道發生了什麼。 – r3plica

+0

如果我做angular.baseService我得到一個錯誤,指出angular.baseService不是一個函數 – r3plica

+0

你可以做一個codepen或什麼?我無法得到這個工作在所有 – r3plica

0

如果您使用(或切換到)ES6或TypeScript,它變得非常容易。

export class Base { 
    // . . . 
} 

然後:

import {app} from '../app'; 
import {Base} from './base'; 

export class Child extends Base { 
    // . . . 
} 

app.service('child', Child); 
0

從你嘗試1:

  1. BaseService尋找apiPath在全球範圍內,
  2. 而角準備依賴你最後的依賴是ImageService,
  3. 首先它會準備dep endency那麼它將從步驟2執行list()方法,
  4. 所有方式的apiPath將把全球範圍內聲明價值,即apiPath = 'images';

解決方案:使用的apiPaththis操作BaseServicelist()下。

工作Plunker