I have an issue with overriding a javascript function. I am working with Odoo POS and I want to override one of the POS JavaScript Function.
In Odoo point_of_sale -> models.js there is a function called set_quantity_by_lot. but it written extending Backbone.Collection. I can extend functions which are belongs to Backbone.Model but not the functions in Backbone.Collection.
This is a code of the function. (I want to extend the set_quantity_by_lot function):
var PacklotlineCollection = Backbone.Collection.extend({
model: exports.Packlotline,
initialize: function(models, options) {
this.order_line = options.order_line;
},
set_quantity_by_lot: function() {
if (this.order_line.product.tracking == 'serial') {
var valid_lots = this.get_valid_lots();
this.order_line.set_quantity(valid_lots.length);
}
}
});
Thank You,
That class is a private variable in module 'point_of_sale.models' if you check the return statement of that module its return exports;
Export contains only this classes that you can override one there methods:
exports = {
PosModel: PosModel,
NumpadState: NumpadState,
load_fields: load_fields,
load_models: load_models,
Orderline: Orderline,
Order: Order,
};
This means you cannot override it or access it. What you need to do Is define a new class PacklotlineCollection
like in the original module and change the code of the method, override the only method that uses it witch is set_product_lot of class Orderline that is returned by the 'point_of_sale.models' module.
odoo.define('techinca_name.models', function (require) {
"use strict";
// to access the classes
var posModels = require('point_of_sale.models')
// require any thing is used in the code too if there is
// define a similar class with a little changes
var PacklotlineCollection = Backbone.Collection.extend({
// change this part
model: posModels.Packlotline,
initialize: function(models, options) {
this.order_line = options.order_line;
},
get_empty_model: function(){
return this.findWhere({'lot_name': null});
},
remove_empty_model: function(){
this.remove(this.where({'lot_name': null}));
},
get_valid_lots: function(){
return this.filter(function(model){
return model.get('lot_name');
});
},
set_quantity_by_lot: function() {
// and this part
if (this.order_line.product.tracking == 'serial') {
var valid_lots = this.get_valid_lots();
this.order_line.set_quantity(valid_lots.length);
}
}
});
// override set_product_lot to use your class not the orignal class
posModels.Orderline.inculde({
// same code the only difference here it will use your own class
set_product_lot: function(product){
this.has_product_lot = product.tracking !== 'none' && this.pos.config.use_existing_lots;
this.pack_lot_lines = this.has_product_lot && new PacklotlineCollection(null, {'order_line': this});
},
});
});
Note: to override a method of class use ClassName.include, extends just create a new class that inherit this ClassName.
Related
I am quite new at SAPUI5 and JS. There is something I do not understand well concerning the module definition and usage. Here is my context:
I want to create a Component my.test.comp that uses an external module object my.test.comp.Service.
So following the best practices, I have the following code:
Service.js:
sap.ui.define([
"sap/ui/base/Object"
], function(BaseObject) {
"use strict";
var modulePath = jQuery.sap.getModulePath("my.test.comp");
var SERVICE_ROOT_PATH = modulePath.lastIndexOf("/") > 0
? modulePath.substring(0, modulePath.lastIndexOf("/"))
: "/test";
var Service = BaseObject.extend("my.test.comp.Service", {
getServiceRootPath: function () {
return SERVICE_ROOT_PATH;
}
});
return Service;
});
And I use this in the Component.js:
sap.ui.define([
"sap/ui/core/Component",
"./Service"
], function(Component, Service) {
"use strict";
return Component.extend("my.test.comp.Component", {
init: function() {
var serviceRootPath = Service.getServiceRootPath();
jQuery.sap.log.error("ServicePathInfo : " + serviceRootPath);
}
});
});
When I run this, I get an error saying that getServiceRootPath is undefined, and throws an error.
So I changed the Service.js as follow:
sap.ui.define([
"sap/ui/base/Object"
], function(BaseObject) {
"use strict";
var modulePath = jQuery.sap.getModulePath("my.test.comp");
var SERVICE_ROOT_PATH = modulePath.lastIndexOf("/") > 0
? modulePath.substring(0, modulePath.lastIndexOf("/"))
: "/test";
var Service = BaseObject.extend("my.test.comp.Service");
Service.getServiceRootPath = function () {
return SERVICE_ROOT_PATH;
};
return Service;
});
And now it is working well. I do not understand what are the differences.
Could someone explain me why?
In JS, there are no classes. There are either plain objects ({}) or functions with constructor that can be called with new.
Accordingly, calling .extend("...") in UI5 returns a function, again, with its constructor as any other functions, ready to be used with new. Your module members (methods, properties, etc.) will be added to the prototype and not to the parent function (Service) itself.
BaseObject.extend("my.test.comp.Service", {
// methods in prototype ...
});
The required Service module (i.e. function) consists of only a constructor function (Service.constructor) and a prototype object (Service.prototype). That is why Service.getServiceRootPath was undefined in your first case. You'll need to call the constructor function with new first:
return Component.extend("my.test.comp.Component", {
init: function() {
const service1 = new Service(); /* returns an object with ..
* __proto__: {
* getServiceRootPath: f ()
* }
*/
const serviceRootPath = service1.getServiceRootPath();
// ...
},
});
(You could also directly access the method with Service.prototype.getServiceRootPath without new)
This also explains why Service.getServiceRootPath worked in the second case. You can add pretty much anything you like to an existing function since functions are ultimately objects too 🙂
It looks like your intention was not to create multiple "services" but a simple object with methods in it. In that case, just return a simple object with methods in your module definition.
sap.ui.define([
// Without "sap/ui/base/Object"
], function() {
"use strict";
//...
return {
getServiceRootPath: function () {
// ...
},
};
});
sap.ui.define([
"sap/ui/core/Component",
"./Service",
], function(Component, Service) {
"use strict";
return Component.extend("my.test.comp.Component", {
init: function() {
const serviceRootPath = Service.getServiceRootPath();
// ...
},
});
});
This will work too.
In your component.js you should import
"my/test/comp/Service"
instead of
"./Service"
Spring has very useful option, that whey I define a bean, I define a scope. If it's singleton, only one instance is created. By prototype, each time a bean is required, a new instance is created.
RequireJS provides by default singletons, so with such simple module:
Singleton.js
define([], function() {
console.log('Instance initialization')
var items = []
var singleton = {
getItems: function() {
return items
},
setItems: function(newItems) {
items = newItems
},
addItem: function(item) {
items.push(item)
}
};
return singleton;
})
and the usage:
require(["showcase/modules/Singleton"], function(Singleton){
Singleton.addItem('item1')
console.log(Singleton.getItems())
})
require(["showcase/modules/Singleton"], function(Singleton){
Singleton.addItem('item2')
console.log(Singleton.getItems())
})
the output will be:
Instance initialization
["item1"]
["item1", "item2"]
Is it possible to define and use the module in such way, that I could switch in the module definition, if I want to use prototype or singleton scope? So in my case, without changing the usage, I'd get:
Instance initialization
["item1"]
Instance initialization
["item2"]
I'm using RequireJS from Dojo, just in case of syntax differences
Well, first of all the problem is that when you import a module using an AMD loader, you will actually get an instance, but the second time you import the same module, the same instance is actually returned (problem 1).
To overcome this problem you should use the factory design pattern to get your instance and also translate your singleton object to a class that can be instantiated (problem 2). Your factory could have a method called getInstance() that accepts a boolean parameter that can toggle between singleton/prototype.
So without changing your usage you won't be able to do this because of the problems I just addressed. The best solution I can come up with (with a factory) is:
Singleton.js
define([], function() {
console.log('Instance initialization');
// Singleton class
var Singleton = function() {
this.items = [];
this.getItems = function() {
return this.items;
};
this.setItems = function(newItems) {
this.items = newItems;
};
this.addItem = function(item) {
this.items.push(item);
}
};
// Factory
var factory = {
singletonInstance: new Singleton(),
getInstance: function(/** Boolean */ isSingleton) {
if (isSingleton === true) {
return this.singletonInstance;
} else {
return new Singleton();
}
}
};
return factory;
});
Usage (singleton)
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(true);
Singleton.addItem('item1');
console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(true);
Singleton.addItem('item2');
console.log(Singleton.getItems());
});
Usage (multiple instances)
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(false);
Singleton.addItem('item3');
console.log(Singleton.getItems());
});
require(["app/Singleton"], function(singletonFactory){
var Singleton = singletonFactory.getInstance(false);
Singleton.addItem('item4');
console.log(Singleton.getItems());
});
In case you're interested in a full example, it's on Plunker.
Eventually you could wrap the factory as a plugin so that you could actually do something like:
require([ "app/Object!singleton", "app/Object!prototype" ], function() {
});
However I don't know if RequireJS also supports this (and if I'm understanding well it should be a generic story for both AMD loaders).
Could any one shows an example for creating a class using prototype.js and how it works.Can anyone provide good examples and tutorials for prototype.js other than its official site?
Creating PrototypeJS Classes is very similar to creating classes in normal OOP languages.
First start off by naming your class
var myClass = Class.create({ });
This will create an empty class - now populate it with methods, if you put a method initialize PrototypeJS will fire that as the constructor
var myClass = Class.create(
{
initialize : function()
{
this.options = 0;
}
});
You can setup anything you want in the initialize() method like default values or just initializing the properties of the class. Lets put in some other methods and show how to instantiate the class.
var myClass = Class.create(
{
initialize : function()
{
this.options = 0;
},
testme : function()
{
this.options++;
},
showme : function()
{
alert(this.options);
return this.options;
}
});
var theClass = new myClass();
Lets take it one more step and call other methods within methods and pass options to the constructor.
var myClass = Class.create(
{
initialize : function(option)
{
this.options = (option ? option : 0);
this.testme();
},
testme : function()
{
this.options++;
},
showme : function()
{
alert(this.options);
return this.options;
}
});
var theClass = new myClass(200);
theClass.showme();
//will alert 201 and return 201
This is cool and all - but what about class inheritance? That is a big thing in OOP - lets say we have a separate class that is a child class of myClass. For any method that you are overriding in the child class you can pass a first variable as $super and that will refer to the parent's method of the same name - similar to a scope resolution
var myChildClass = Class.create(myClass,
{
initialize : function($super,option)
{
$super(option);
// the child class needs option's default value at 150 or whatever is
// passed so run the parent initialize first and then redefine the
// option property
this.option = (option ? option : 150);
// you can still run methods in the parent that are not overridden in
// the child
this.testme();
}
});
var child = new myChildClass();
child.showme();
//will alert() 151 and return 151
I hope this is helpful for you.
Here are some more complex real world examples from my github
https://github.com/jwestbrook/Prototype.Growler
https://github.com/jwestbrook/Prototype.Watermark
https://github.com/jwestbrook/bootstrap-prototype
I have code that looks like this:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
}
Adding methods to baseClass is fine, I just use
baseClass.prototype.newMethod = function () {
// NEW CODE
}
My question is how should I add methods to subClass? Is the only way to simply make it a public method?
######## EDIT ##############
OK so I've rearranged the code so the subClass is outside the baseClass. I pass in baseClass so subClass can still access the properties of the instance of baseClass.
var baseClass = function() {
var base = this;
this.property_a = 1;
this.property_b = 5;
var sub = new subClass(base);
// CODE
}
var subClass = function(parent) {
var sub = this;
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
this is fine and works, but now I have a new problem of when I add a method using prototype:
subClass.prototype.method_b = function(){
return sub.property_c + parent.property_b;
}
I get an error saying parent isn't defined.
Basically I have a fairly simple web application that has two sides, a viewing side and an editing side. I build the base class which includes everything necessary for viewing, and I want to add the methods required for editing in a different file so they're only loaded when a user is on the editing page.
Why do you declare that subclass in the base class? Doesn't make sense to me.
You can add to the subclass's prototype whereever it is in you scope. In your code it would be
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype = {
...
}
}
But I'd suggest to put it out of the base class constructor. If you want it private for some reason, add a closure:
(function(){
baseClass = function() { // public
// CODE
}
baseClass.prototype = {...};
var subClass = function() { // private
// MORE CODE
}
subClass.prototype = Object.create(baseClass.prototype);
subClass.prototype.newMethod = function () { ... }
})()
EDIT to answer the extended question:
Ah, subClass doesn't inherit from baseClass! We had expected that, otherwise it may be OK to have it inside the constructor. Then, the same prototype could have been added to each of the different subClass constructors:
var subproto = {
method_b: = function(){
// manipulate "this"
},
...
};
function baseClass() {
// some code
function sub() {
// is a constructor for subs which belong to this specif base intance
...
}
sub.prototype = subproto; // the sub constructors of each base instance
// have the same prototype
var x = new sub(),
y = new sub(); // example usage of the sub constructor
}
baseClass.prototype = {...}
Else, if you want one common sub constructor (outside of function baseClass), you may give the base instance the sub belongs to as an argument to the constructor - as you did. Of course the sub (both internal and external methods) can only access public properties of that base instance.
The mistake you made in your rearranged code is that your prototype ("external") methods tried to access the private parent variable from the sub constructor. As you say, "error saying parent isn't defined".
var subClass = function(parent) {
var sub = this;
this.parent = parent; // make it public
this.property_c = 1;
this.method_a = function() {
return sub.property_c + parent.property_a;
}
// MORE CODE
}
subClass.prototype.method_b = function(){
// prototype functions can only access public properties
// i.e. privileged methods, public attributes and other prototype properties
return this.property_c + this.parent.property_b;
}
You will have to define the methods in the same context as you define subClass:
var baseClass = function() {
// CODE
var subClass = function() {
// MORE CODE
}
subClass.prototype.newMethod = function () { ... }
}
If that's not possible, then you will need to expose subClass to the appropriate context or provide a mechanism from baseClass to extend subClass.
If you really want to keep the subclass private, you could hide the definitions in a closure:
var BaseClass = (function() {
function BaseClass() { ... };
function SubClass() { ... };
BaseClass.prototype.foo = function() { ... };
SubClass.prototype.foo = function() { ... };
return BaseClass;
})();
I have personally found this kind of closure-enforced protection to be more trouble than it's worth (ex, makes debugging more difficult)… But if you wanted to do it, that's how you would.
I'm struggling with how best to combine javascript Classes and jQuery plugins. This question isn't very specific, what I'm hoping for is pointers to more resources.
Basically, I want to store state data and private methods in a class, and then extend each jQuery object which I call my plugin on to have those private methods and properties. Such that inside the plugin I can call methods directly off the jQuery object.
I read jQuery plugin design pattern (common practice?) for dealing with private functions, specifically David's answer, however this initializes a new Class each time, and thus can't be used to save the state of the object.
I also found http://fuelyourcoding.com/jquery-plugin-design-patterns-part-i/, which recommends creating a class and then storing it in .data().
I think ideally what I want to end up with is code that looks like
(function( $ ){
var methods = {
init : function( options ) { // Initialize each object with a state and private methods },
show : function( ) {
// testFoo() is a private method that checks the element's state
if(this.testFoo()){
// Relying on jQuery's html() method
this.html() = this.fooTemplate();
}
}
};
// Boiler plate plugin from http://docs.jquery.com/Plugins/Authoring
$.fn.myPlugin = function( method ) {
// Method calling logic
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.myPlugin' );
}
};
})( jQuery );
Finally, it doesn't seem like I can bake the private methods into the plugin directly because methods like "testFoo()" will return a boolean, and therefore aren't chainable.
Thoughts? Am I approaching this the right way? Is there another design pattern I should be using? Perhaps not using jQuery plugin architecture at all?
Here's a proposed solution. It combines few different approaches (John Resig's inheritance model and Alex Saxton's plugin inheritance model).
Define your inheritable plugin:
(function ($) {
My.Plugin = Class.extend({
/*
* Initialization (constructor)
*/
init: function (element, meta) {
var $meta = $.extend({ name: "pluginName" }, meta);
// Call the base constructor
this._super(element, $meta);
// TODO: Add custom initialization code like the following:
// this._testButton = $('.testButton', element).get(0);
},
/*
* Public methods
*/
show: function() {
alert('This is a public method');
},
/*
* Private methods
*/
// DEMO: Overriding the base _paint method:
_paint: function () {
// "this._super()" is available in all overridden methods
// and refers to the base method.
this._super();
alert('TODO: implement myPlugin._paint!');
}
});
// Declare this class as a jQuery plugin
$.plugin('my_plugin', My.Plugin);
})(jQuery);
Define Base class
(function () {
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function () { };
// Create a new Class that inherits from this class
Class.extend = function (prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] =
typeof prop[name] == "function"
&& typeof _super[name] == "function"
&& fnTest.test(prop[name])
? (function (name, fn) {
return function () {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name])
: prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
Plugin Creation
(function ($) {
// The "inheritance plugin" model
// [http://alexsexton.com/?p=51][1]
$.plugin = function (name, object) {
$.fn[name] = function (options) {
var instance = $.data(this, name, new object(this, options));
return instance;
};
};
})(jQuery);
Calling your plugin from javascript:
$('#someElem').my_plugin({options: {}, data: {} /* you can modify your plugin code to accept anything */}).show();
Note:
Private methods here are marked as _methodName. It's pure convention. If you really want to hide them, you can use module pattern (google for it or here's one for starters: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth)
Is this what you're looking for?