angularjs с наследованием ООП в действии



Аннотация



я работаю над приложением, которое использует angular в качестве фреймворка на стороне клиента, angular в настоящее время качается, и я действительно счастлив использовать его, Хотя теперь я считаю, что я использую для большого копирования и вставки кода, который я хотел бы организовать в иерархию классов. Например диалоги имеют общий набор функций, они должны быть открыты, закрыты, код, который предоставляет typeahead функциональность также является первым кандидатом на наследование от некоторых родительских BaseTypeaheadClass, хотя одна вещь, которую я не нашел в angular, - это стандартный способ организации этих иерархий. Оба контроллера, службы, провайдеры используют обычные функции javascript, под которыми могут быть расширены с помощью prototype, так что мой вопрос:



вопрос



каков угловой способ организации функций моего класса, существуют ли какие-либо стандартные механизмы, которые позволят выводить один класс из другого



П. С.



мои догадки по проблема:




  • определите реализацию базовых классов как сервисов, в результате они будут легко вводиться в любой контроллер или другие сервисы, где этот конкретный класс будет необходим

  • определение OOP обслуживание и обеспечивает методы как define,derive и т. д. это будет использоваться для создания базовых / производных классов




Edit



прошло некоторое время с того момента, когда я впервые задал свой вопрос. С тогда я вышел с подходом, который я успешно использую в нескольких проектах, что мне очень нравится и хочу поделиться со всеми.



в настоящее время angular не предоставляет никаких конструкций для организации иерархий классов, и это жаль, так как более или менее большое приложение не может удовлетворить только модель/представление/контроллер/... конструкции, он должен организовать его код в объекты ООП.



я работаю в области веб-разработки уже довольно давно и я не видел ни одного корпоративного проекта, который бы массово использовал ООП с JavaScript. То, что я видел, было огромной и хорошо организованной логикой на стороне сервера / базы данных + близко к бесконечным спагетти javascript, смазанным зоопарком фреймворков и библиотек на стороне клиента.



нет MVVM, MVP фреймворки, такие как нокаут.js, позвоночник, другое... способны заменить ООП как таковой. Если вы не используете основные принципы ориентированного программирования, такие как классы, объекты, Наследование, абстракция, полиморфизм вы находитесь в глубокой беде, то, что вы в конечном итоге является мега длинным javascript спагетти.



что касается углового, я думаю, что это структура очень сильно отличается от нокаута.js / позвоночник.js / любые другие MVV-любые рамки, но, согласно моей практике, это также не серебряная пуля, способная заменить ООП. Когда я пытаюсь не использовать ООП с Angular, я получаю дублирующую логику, расположенную в основном в контроллерах. И, к сожалению, нет (Я не нашел) чистый и угловой способ победить эту проблему.



но я успешно (я думаю) решил эту проблему.



я использовал компактный, нулевой зависимости lib, который просто реализует John Resig's Simple JavaScript Inheritance (https://github.com/tracker1/core-js/blob/master/js-extensions/040-Class.js с помощью этой библиотеки я смог создавать / наследовать / создавать абстрактные методы / переопределять их, другими словами делать все, что я привык на стороне сервера.



пример использования:



Application.factory('SomeChildObject', ['$http', 'SomeParentClass', function ($http, SomeParentClass) {
var SomeChildClass = SomeParentClass.extend({
init: function() { // Constructor
this._super.init(123, 231); // call base constructor
},
someFunction: function() {
// Notice that your OOP now knows everything that can be injected into angular service, which is pretty cool :)
$http({method: 'GET', url: '/someUrl'}).then(function(){
this._super.someFunction(); // call base function implementation
});
}
});

// return new SomeChildClass(); // We are not returning instance here!

return SomeChildClass; // Service is a function definition not an instance of an object
}]);

// So now we can both use this service in angular and have the ability to extend it using the `extend` method call, like so:
Application.controller('MegaController', ['$scope', 'SomeChildClass', function ($scope, SomeChildClass) {
$scope.someObject = new SomeChildClass();
}]);


ООП + угловая игра очень хорошо, объекты, созданные в угловом контексте, могут автоматически использовать инъекцию зависимостей через службы, поэтому вам не нужно вводить экземпляры в ваши конструкторы ООП, и этот факт делает вашу иерархию ООП очень тонкой и свободной от ненужных вещей, которые должны быть (и обрабатываются) angular.js



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



еще одно редактирование



недавно я столкнулся с несколькими проблемами с оригинальным классом.реализация js, следующим образом:



1) Если вы будете передавать ссылку на свои методы экземпляра в качестве обратных вызовов другим методам, эти методы могут работать не так, как вы ожидаете. Они потеряют ссылку на this. В таком случае вы будете ожидать увидеть ваш текущий объект внутри this но это будет либо топ уровень Window или другой объект контекста в зависимости от способа обратного вызова метода. Это происходит из-за архитектуры JavaScript. Для того, чтобы бороться с этой проблемой специальный ClassMember функция, которая указывает Class чтобы привязать метод к контексту объекта при его создании (проверьте Usage ниже для получения дальнейших указаний).



2) очевидно, что первоначально Class.js реализация ничего не знает об угловом типе объявлений метода контроллера, т. е.



Class.extend('YourClassDisplayName', {
ctor: function () {
// Some useful constructor logic
},
controller: ['$scope', '$attrs', function ($scope, $attrs) {
// Do something with $scope and $attrs
}]
});


текущая реализация понимает выше синтаксис



3) при использовании вышеуказанного подхода без соответствующей обработки он сломал бы угловой $$annotate ' на процесс так ссылаясь на выше пример это сделало бы невозможным ввести $scope и $attrs в into ClassMember метод, или переопределенный метод, который использует this.base(...) звонки. Так что это тоже исправлено.



Gotchas:



1) при использовании this.base(...) в асинхронном режиме обработчик операций (что-то вроде $http.get(..., function() { self.base(...); })) обратите внимание, что this.base(...) вызов имеет ограниченное время жизни и как только метод возвращает this.base(...) перестает существовать. Таким образом, вы должны сохранить ссылку на базовый метод явно, если вы планируете вызывать базовые методы асинхронным способом. я.е:



...
var self = this;
var base = this.base;
...
$http.get(..., function () {
base.call(self, ...); // or base.apply(self, ...), or base() if you don't care about `this`
})


я решил все вышеперечисленные проблемы (за исключением одной gotcha, которая не может быть решена из-за архитектуры JavaScript) и хотел бы поделиться со всеми, надеюсь, что вы выиграете от это:



/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype

* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------

var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},

myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},

myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});

var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},

myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},

myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});

var x = new X();
var y = new Y();

x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]

x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]

y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;

y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]

*/

angular.module('app').factory('ClassMember', function () {
return function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
} else {
return new ClassMember(fn);
}
};
});

angular.module('app').factory('Class', function (ClassMember) {
var runtime = { initializing: false },
fnTest = /xyz/.test(function() { xyz; }) ? /bbaseb/ : /.*/,
FN_ARGS = /^functions*[^(]*(s*([^)]*))/m,
STRIP_COMMENTS = /((//.*$)|(/*[sS]*?*/))/mg;

var toString = Object.prototype.toString;

// The base Class implementation (does nothing)
function Class() { };

Class.members = { };

// Create a new Class that inherits from this class
Class.extend = function extend(displayName, properties) {
var array;

var targetMembers = {};
var sourceMembers = this.members;

for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}

var base = this.prototype;

// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;

// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];

// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;

var item = array[array.length - 1];

if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}

var isClassMember = property instanceof ClassMember;

if (isClassMember) {
property = property.fn;
}

if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {n
var prevBase = this.base;n
var hasBase = "base" in this;n
n
// Add a new .base() method that is the same methodn
// but on the super-classn
n
this.base = base[propertyName];n
n
// The method only need to be bound temporarily, so wen
// remove it when we're done executingn
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');n
n
if (hasBase) {n
this.base = prevBase;n
} else {n
delete this["base"];n
}n
return ret;n
}'))(propertyName, fn, base);
})(name, property);
}

if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}

if (array) {
array[array.length - 1] = property;

property = array;
}

prototype[name] = property;
} else {
prototype[name] = property;
}
}
}

var membersArray = [];
for (var i in targetMembers) {
if (targetMembers.hasOwnProperty(i)) {
membersArray.push({ name: i, fn: targetMembers[i] });
}
}

// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {n
if (!runtime.initializing && this.ctor)n
{n
var length = members.length;n
for (var i = 0; i < length; i++)n
{n
var item = members[i];n
this[item.name] = (function (me, fn) {n
var args = fn.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];n
return args ? (new Function('me', 'fn', 'return function (' + args + ') { return fn.call(me, ' + args + '); }'))(me, fn) : function () { return fn.call(me); };n
})(this, item.fn);n
n
}n
this.ctor.apply(this, arguments);n
}n
}"))(runtime, membersArray, FN_ARGS, STRIP_COMMENTS);

ChildClass.members = targetMembers;

// Populate our constructed prototype object
ChildClass.prototype = prototype;

// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;

// And make this class extendable
ChildClass.extend = extend;

return ChildClass;
};

return Class;
});




еще одно редактирование



в конце концов я наткнулся на другую проблему, связанную с реализацией оригинального John Resig в отношении angular, и проблема связана с процессом аннотации angular (используется для инъекции зависимостей), который использует функцию.прототип.toString () и некоторые регулярные выражения для извлечения имен зависимостей. И проблема с оригинальной реализацией заключается в том, что она не ожидает этого, и поэтому вы не являетесь возможность объявлять методы, которые принимают зависимости, поэтому я немного изменил реализацию, чтобы справиться с ранее описанной проблемой, и вот она:



/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*
* Inspired by base2 and Prototype

* Angular adaptations by Denis Yaremov http://github.com/lu4
* Usage:
---------------------------------

var X = Class.extend('X', {
ctor: function () {
this.name = "I'm X";
},

myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},

myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});

var Y = Class.extend('Y', {
ctor: function () {
this.name = "I'm Y";
},

myOrdinaryMethod: function (x, y, z) {
console.log([this.name, x, y, z]);
},

myClassMemberMethod: ClassMember(function (x, y, z) {
console.log([this.name, x, y, z]);
})
});

var x = new X();
var y = new Y();

x.myClassMemberMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myClassMemberMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]

x.myOrdinaryMethod('a', 'b', 'c'); // ["I'm X", "a", "b", "c"]
y.myOrdinaryMethod('u', 'v', 'm'); // ["I'm Y", "u", "v", "m"]

y.theirOrdinaryMethod = x.myOrdinaryMethod;
y.theirClassMemberMethod = x.myClassMemberMethod;

y.theirOrdinaryMethod('a', 'b', 'c'); // ["I'm Y", "a", "b", "c"]
y.theirClassMemberMethod('u', 'v', 'm'); // ["I'm X", "u", "v", "m"]

*/


angular.module('homer').factory('Class', function () {
function ClassMember(fn) {
if (this instanceof ClassMember) {
this.fn = fn;
return this;
} else {
return new ClassMember(fn);
}
}

function ClassEvent() {
if (this instanceof ClassEvent) {
return this;
} else {
return new ClassEvent();
}
}

var runtime = { initializing: false },
fnTest = /xyz/.test(function () { xyz; }) ? /bbaseb/ : /.*/,
fnArgs = /^functions*[^(]*(s*([^)]*))/m,
stripComments = /((//.*$)|(/*[sS]*?*/))/mg;

var toString = Object.prototype.toString;

// The base Class implementation (does nothing)
function Class() { };

Class.events = {};
Class.members = {};

// Create a new Class that inherits from this class
Class.extend = function Extend(displayName, properties) {
var array;

var targetEvents = {};
var sourceEvents = this.events;

var targetMembers = {};
var sourceMembers = this.members;

for (var eventName in sourceEvents) {
if (sourceEvents.hasOwnProperty(eventName)) {
targetEvents[eventName] = sourceEvents[eventName];
}
}

for (var memberName in sourceMembers) {
if (sourceMembers.hasOwnProperty(memberName)) {
targetMembers[memberName] = sourceMembers[memberName];
}
}

var base = this.prototype;

// Instantiate a base class (but only create the instance,
// don't run the ctor constructor)
runtime.initializing = true;
var prototype = new this();
runtime.initializing = false;

// Copy the properties over onto the new prototype
for (var name in properties) {
if (properties.hasOwnProperty(name)) {
// Check if we're overwriting an existing function
var property = properties[name];

// Support angular's controller/service/factory declaration notation
if (toString.call(property) === '[object Array]') {
array = property;

var item = array[array.length - 1];

if (toString.call(item) === '[object Function]' || item instanceof ClassMember) {
property = array[array.length - 1];
} else {
array = null;
}
} else {
array = null;
}

var isClassMember = property instanceof ClassMember;

if (isClassMember) {
property = property.fn;
}

var isClassEvent = property instanceof ClassEvent;

if (isClassEvent) {
property = (function() {
function Subscriber(fn) {
Subscriber.listeners.push(fn.bind(this));
};

Subscriber.listeners = [];
Subscriber.fire = function() {
var listeners = Subscriber.listeners;

for (var i = 0; i < listeners.length; i++) {
var result = listeners[i].apply(this, arguments);

if (result !== undefined) return result;
}

return void 0;
}

return Subscriber;
})();
}

if (typeof property === "function") {
if (typeof base[name] === "function" && fnTest.test(property)) {
property = (function (propertyName, fn) {
var args = fn.toString().replace(stripComments, '').match(fnArgs)[1];
return (new Function('propertyName', 'fn', 'base', 'return function (' + args + ') {n
var prevBase = this.base;n
var hasBase = "base" in this;n
n
// Add a new .base() method that is the same methodn
// but on the super-classn
n
this.base = base[propertyName];n
n
// The method only need to be bound temporarily, so wen
// remove it when we're done executingn
var ret = fn.call(this' + (!!args ? (', ' + args) : args) + ');n
n
if (hasBase) {n
this.base = prevBase;n
} else {n
delete this["base"];n
}n
return ret;n
}'))(propertyName, fn, base);
})(name, property);
}

if (isClassEvent) {
targetEvents[name] = property;
} else {
delete targetEvents[name];
}

if (isClassMember) {
targetMembers[name] = property;
} else if (name in targetMembers) {
delete targetMembers[name];
}

if (array) {
array[array.length - 1] = property;

property = array;
}

prototype[name] = property;
} else {
prototype[name] = property;
}
}
}

var eventsArray = [];
for (var targetEventName in targetEvents) {
if (targetEvents.hasOwnProperty(targetEventName)) {
eventsArray.push({ name: targetEventName, fn: targetEvents[targetEventName] });
}
}

var membersArray = [];
for (var targetMemberName in targetMembers) {
if (targetMembers.hasOwnProperty(targetMemberName)) {
membersArray.push({ name: targetMemberName, fn: targetMembers[targetMemberName] });
}
}

// All construction is actually done in the ctor method
var ChildClass = (new Function("runtime", "events", "members", "FN_ARGS", "STRIP_COMMENTS", "return function " + (displayName || "Class") + "() {n
if (!runtime.initializing && this.ctor)n
{n
var length = members.length;n
var bind = function (me, $$fn$$) {n
var args = $$fn$$.toString().replace(STRIP_COMMENTS, '').match(FN_ARGS)[1];n
var result = args ? (new Function('me', '$$fn$$', 'return function (' + args + ') { return $$fn$$.apply(me, arguments); }'))(me, $$fn$$) : function () { return $$fn$$.apply(me, arguments); };n
return result;n
};n
for (var i = 0; i < length; i++)n
{n
var item = members[i];n
var fn = item.fn;n
var name = item.name;n
var property = this[name] = bind(this, fn);n
if (fn.fire) {n
property.fire = bind(this, fn.fire);n
}n
if (fn.listeners) {n
property.listeners = fn.listeners;n
}n
}n
n
var length = events.length;n
for (var i = 0; i < length; i++)n
{n
var item = events[i];n
var fn = item.fn;n
var name = item.name;n
var property = this[name] = bind(this, fn);n
if (fn.fire) {n
property.fire = bind(this, fn.fire);n
}n
if (fn.listeners) {n
property.listeners = fn.listeners;n
}n
}n
this.ctor.apply(this, arguments);n
}n
}"))(runtime, eventsArray, membersArray, fnArgs, stripComments);

ChildClass.members = targetMembers;

// Populate our constructed prototype object
ChildClass.prototype = prototype;

// Enforce the constructor to be what we expect
ChildClass.prototype.constructor = ChildClass;

// And make this class extendable
ChildClass.extend = Extend;
ChildClass.event = ClassEvent;
ChildClass.member = ClassMember;

return ChildClass;
};

Class.member = ClassMember;
Class.event = ClassEvent;

return Class;
});
642   3  

3 ответов:

ваши догадки вполне применимо.

вы можете повторно использовать функциональность, определенную в родительских контроллерах, просто вызывая методы, прикрепленные к родительской области:

HTML

<div ng-controller="ParentCtrl">
    <!-- Something here ... -->
    <div ng-controller="ChildCtrl">
        <!-- Something here ... -->
    </div>
    <!-- Something here ... -->
</div>

JavaScript

function ParentCtrl($scope) {
    $scope.parentMethod = function () {
        //method body
    };
}

function ChildCtrl($scope) {
    $scope.childMethod = function () {
        //functionality
        $scope.parentMethod();
        //functionality
    };
}

если вы хотите использовать подход JavaScript с наследованием прототипов, вы можете использовать:

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

function Parent($scope) {
    $scope.name = 'Superhero';    

    $scope.clickParent = function() {
        $scope.name = 'Clicked from base controller';
    }    
}

function Child($scope, $injector) {

    debugger;
    $injector.invoke(Parent, this, {$scope: $scope});

    $scope.name = 'Superhero Child';

    $scope.clickChild = function(){
        $scope.clickParent();
    }       
}
Child.prototype = Object.create(Parent.prototype);

http://jsfiddle.net/mhevery/u6s88/12/

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

(function () {

function ParentService(arg1) {
   this.arg1 = arg1;
}

function ChildService(arg1, arg2) {
   ParentService.call(this, arg1);
   this.arg2 = arg2;
}

ChildService.prototype = new ParentService();

app.service('ChildService', ChildService);

}());

также проверить этой Обсуждение и сообщение в блоге о наследовании в AngularJS я в курсе.

позвольте мне дать вам мое мнение об угловой / наследственной ситуации.

вы не делаете наследование класса/прототипа в Angular.js. Это может быть трудно проверить, и это проблема. Для тех, кто ищет "наследование" в Angular, я рекомендую следующее:

ваш базовый класс контроллера. Контроллер в любом случае является абстрактной моделью, поэтому он идеально подходит для этой цели. Используйте $ scope.функция init() в вашем контроллере, но не вызывайте это оттуда!

если вы хотите "расширить" функциональность вашего контроллера, используйте директивы. В функции директивы link () вызовите $scope контроллера.инициализация.)( (при компиляции сначала выполняются контроллеры angular, а затем функции директивной ссылки). Если бы область имела $scope.name='base', в директивной ссылке вы сможете переопределить $scope.name=child, и после этого запустите $scope.инициализация.)(

но подождите! Но это позволяет только одноуровневое наследование. - Да, это истинный. Но если вы ищете многоуровневое наследование, вы должны использовать услуги.

многоуровневое наследование-это не что иное, как совместное использование одного и того же кода в иерархической структуре классов. Для этого воспользуйтесь услугами, и бросьте эти службы с инжектором зависимостей в ваши директивы. Су легко. Это должно быть легко сделать, легко понять, и тесты проходят гладко.

директивы очень мощные инструменты, потому что вы можете динамически комбинировать частичные файлы с контроллерами.

Я думаю, что ваши догадки довольно хорошо, и я играл с несколько подходов, но все они оказались более многословными, чем я надеялся.

У меня была проблема, когда я разработал сложный диалог в качестве вкладки в нашем интерфейсе администратора, но я хотел почти идентичный диалог во всплывающем окне в разделе пользователя, но данные будут заполнены из другого источника, и будет несколько дополнительных кнопок. В принципе отличный кандидат на классическое наследство. Для стороны пользовательского интерфейса I использовал шаблон, который был включен в двух местах с разными контроллерами. Но чтобы избежать дублирования сложной логики пользовательского интерфейса в контроллерах, я хотел использовать наследование.

метод наследования области несколько зависит от структуры приложения и не был подходящим, потому что два UI находились в разных приложениях. Подход к помещению повторно используемого кода в службы будет в конечном итоге подробным, поскольку мне нужно было бы, чтобы каждый метод контроллера вызывал эквивалентный метод на сервисе. Поэтому я использовал следующий простой подход к наследованию JavaScript:

/**
 * Effective base class for Thing Controllers.
 * This should be considered abstract since it does not define
 * $scope.readData() or $scope.saveData() which may be called from its
 * other functions.
 */
function BaseThingController($scope, $http){
    $scope.data = []; // local data store;
    $scope.validateForm(){...}
    $scope.edit(){...}
    $scope.cancel(){...}
    $scope.reset(){...}
    $scope.otherMethod1(){...}
    $scope.otherMethod2(){...}
    $scope.otherMethod3(){...}
}

/**
 * AdminThingController effectively extends BaseThingController
 */
function AdminThingController($scope, $http){
    // Calling BaseThingController as a function defines all the needed 
    // functions and properties in our scope.
    BaseThingController($scope, $http)

    $scope.readData(){
       // $scope.data = data from admin data source
    }

    $scope.saveData(newData){
       // save to special admin service
    }

    // initialize local data
    $scope.readData()
}

/**
 * UserThingController effectively extends BaseThingController
 */
function UserThingController($scope, $http){
    // Calling BaseThingController as a function defines all the needed 
    // functions and properties in our scope.
    BaseThingController($scope, $http)

    $scope.readData(){
       // $scope.data = data from user data source
    }

    $scope.saveData(newData){
       // save to user service
    }

   /**
    * Overriding base class behaviour here
    */
   $scope.otherMethod1(){...}

    // initialize local data
    $scope.readData()

}

поэтому я не использовал наследование прототипов, поскольку $scope легко доступен. Но я получил все поведение от базового контроллера и только добавил или переопределил то, что я хочу. Мои представления могут быть настроены с любым контроллером и будут работать без каких-либо изменений.

Comments

    Ничего не найдено.