javascript override class variable - javascript

I have class with variables, I want change variable value by another function in external file
Class code
frappe.ui.Notifications = class Notifications {
constructor() {
frappe.model
.with_doc('Notification Settings', frappe.session.user)
.then(doc => {
this.notifications_settings = doc;
this.make();
});
}
make() {
this.$dropdown = $('.navbar').find('.dropdown-notifications');
this.$dropdown_list = this.$dropdown.find('.notifications-list');
this.$notification_indicator = this.$dropdown.find('.notifications-indicator');
}
};
i wand change variable this.$dropdown
frappe.ui.Notifications.$dropdown = $('.Header').find('.dropdown-item-notifications');

The Notification class instance is set at frappe.frappe_toolbar.notifications. You can use it to override the property.
frappe.frappe_toolbar.notifications.$dropdown = $('.Header').find('.dropdown-item-notifications');

Related

Get the names of the parameters of the wrapped function

I want to use the methods of the Minio class without specifying all their parameters, but substituting some of the parameters automatically. How do I do it...
I get all the class methods from the prototype of the Minio class and dynamically create wrappers for them in my class.
For each wrapper method, I get the parameter names from the original method of the Test class.
If there is one in the list of parameters that I want to omit when calling my wrapper method, then I add it to the list of arguments and call originalMethod.apply(this.minioClient, args).
Everything was fine until there were methods that were already wrapped.
I need to get the parameter list of the bucketExists method from outside the Minio class. Any idea how to get parameter names from such a wrapped method?
// minio/dist/main/helpers.js
exports function promisify(fn){
return function(){
const args = [...arguments];
fn.apply(this, args);
}
}
// minio/dist/main/minio.js
class Minio{
bucketExists(bucketName){
return bucketName;
}
methodThatNotWrappedByPromisifyAndWorksFine(bucketName){
return bucketName;
}
}
module.exports = Minio;
Minio.prototype.bucketExists = (0,helpers.promisify)(Minio.prototype.bucketExists)
I want to give an instance of my class with methods wrapped from the original class link the ability to work with only one bucket, that was passed to the my class constructor, without the ability to specify some other one after initialize.
My wrapper
const proxyHandler = () => {
return {
apply: (target, thisArg, argumentsList) => {
const funcParams = getMethodParamNames(target.source ? target.source.functionForWrap : target);
const bucketNameIndex = funcParams.indexOf("bucketName");
const regionNameIndex = funcParams.indexOf("region");
if (bucketNameIndex >= 0) {
argumentsList.splice(bucketNameIndex, 0, this.bucket.name);
}
if (regionNameIndex >= 0) {
argumentsList.splice(regionNameIndex, 0, this.bucket.region);
}
try {
return target.apply(this.minioClient, argumentsList);
} catch (error) {
logger.engine.error(`S3 '${this.bucket.name}' ${target} error: ${error.message}`, error.stack);
}
},
}
}
getMethods(this.minioClient).forEach(func => {
this[func] = new Proxy(this.minioClient[func], proxyHandler());
})
Solved the problem by overriding the method wrapper like this.
const MinioHelpers = require('minio/dist/main/helpers');
const origMinioPromisify = MinioHelpers.promisify;
MinioHelpers.promisify = (functionForWrap) => {
console.log("PATCHED!", functionForWrap);
var fn = origMinioPromisify(functionForWrap);
//from this i'll get all need information about wrapped function
fn.source = {
functionForWrap,
promisify: origMinioPromisify,
}
return fn
}
var Minio = require('minio');

Call method from one class when calling methods from another

I have two classes: first on checks that file exists and it's valid; second one make some stuff with that file:
class Validator {
constructor(){
this.file = './file.json';
}
check(){ ... }
}
class Modificator {
action1(){ ... }
action2(){ ... }
}
What I want is the method from first class automatically calls inside each method from the second class.
It's a bit tricky stuff, but I'm really don't want to do it manually, like so:
class Validator {
constructor(){
this.file = './file.json';
}
static check(){ ... }
}
class Modificator {
action1(){
let status = Validator.check();
...
}
action2(){
let status = Validator.check();
...
}
}
By using a wrapper
class Validator {
static check () {console.log('checked')}
static checkCbk (fn) {
return _ => {
this.check()
//then callback
fn()
}
}
}
class Modificator {
//via public instance field
action1 = Validator.checkCbk(function () {
console.log('mod::action1')
})
}
//or by prototype
Modificator.prototype.action2 = Validator.checkCbk(function(){
console.log('mod::action2')
})
var m = new Modificator()
m.action1()
m.action2()
However notice that if you were to subclass Modificator, you could forget to rewrap your methods...
By making a contract
More commonly by making a contract and delegating to implem if contract is fulfilled.
This way you don't have to worry when extending since check is made in base class anyway.
class Validator {
static check () {console.log('checked')}
}
class Contract {
action1 () {
Validator.check()
this._action1()
}
}
class M2 extends Contract {
_action1 () {
console.log('mod2::action1')
}
}
var m = new M2()
m.action1()

'this' does not reference current object context during intercept of Binding Behavior

In an Aurelia app, I am using a binding-behavior. It looks like this:
<div id="slider" ej-slider="e-value.two-way:controller.item.progress & intercept:controller.saveChange;" ></div>
The intercept binding behavior from here is binding controller.saveChange which does get called.
However, the issue is that within that method, this refers not to the controller, but to the binding. So I can't access the methods and properties of the controller which are needed to do the actual save.
This is what the Binding Behavior Looks like:
export class InterceptBindingBehavior {
readonly interceptMethods = ['updateTarget', 'updateSource', 'callSource'];
bind(binding, scope, interceptor) {
let i = this.interceptMethods.length;
while (i--) {
let method = this.interceptMethods[i];
if (!binding[method]) {
continue;
}
binding[`intercepted-${method}`] = binding[method];
let update = binding[method].bind(binding);
binding[method] = interceptor.bind(binding, method, update);
}
}
unbind(binding, scope) {
let i = this.interceptMethods.length;
while (i--) {
let method = this.interceptMethods[i];
if (!binding[method]) {
continue;
}
binding[method] = binding[`intercepted-${method}`];
binding[`intercepted-${method}`] = null;
}
}
}
How do I resolve this?
Related to my comment, as a quick&dirty fix I would try to pass the class and the method separately as arguments. I tested it and it does work. But maybe some aurelia experts know a better way how to handle this:
html
<div id="slider" ej-slider="e-value.two-way:controller.item.progress & intercept:controller:'saveChange'"></div>
InterceptBindingBehavior.ts
export class InterceptBindingBehavior {
readonly interceptMethods = ['updateTarget', 'updateSource', 'callSource'];
bind(binding, scope, interceptorClass, interceptorMethod) {
let i = this.interceptMethods.length;
while (i--) {
let method = this.interceptMethods[i];
if (!binding[method]) {
continue;
}
binding[`intercepted-${method}`] = binding[method];
let update = binding[method].bind(binding);
binding[method] = interceptorClass[interceptorMethod].bind(interceptorClass, method, update);
}
}
unbind(binding, scope) {
let i = this.interceptMethods.length;
while (i--) {
let method = this.interceptMethods[i];
if (!binding[method]) {
continue;
}
binding[method] = binding[`intercepted-${method}`];
binding[`intercepted-${method}`] = null;
}
}
It looks like the original InterceptBindingBehavior only supports a method directly on the current binding, it use interceptor.bind(binding, ... to ensure this is properly set.
But you want this to be controller, not current binding.
The easy fix is to enforce this by yourself.
Either in your component's constructor
export class YourComponent {
constructor(...) {
// guess you have this.controller = controller; somewhere
this.controller.saveChange = this.controller.saveChange.bind(this.controller);
}
}
Or in your controller's constructor
export class Controller {
constructor(...) {
this.saveChange = this.saveChange.bind(this);
}
}

Class Scope with method called from subclass JS

I have a subclass that does some validation stuff that calls a method in the parent class that extends it, this is working in all places except when I need to access the local scope in the parent class, see example below
subclass
export default class ElementEvent extends Core {
constructor(events){
super(events);
this.validation = this.validateEvent();
this.element = this.getElement();
this.triggered = false;
this.player = false;
this.waitForElementDelay = 3000;
if (this.validation){
if (this.element){
this.processEvent();
} else {
this.waitForElement();
}
}
waitForElement(){
const interval = setInterval(()=>{
const el = this.getElement();
if (el){
this.element = el;
this.processEvent();
clearInterval(interval);
}
}, this.waitForElementDelay)
}
}
parent
export default class Reading extends ElementEvent {
constructor(event) {
super(event);
this.readingZoneHeight = 50;
this.wordsPerMinute = 300;
this.timer = 0;
}
processEvent() {
//this.elementEntryPoint = this.getElementEntryPoint();
//this.elementExitPoint = this.getElementExitPoint();
console.log(this);
console.log(this.readingZoneHeight);
window.addEventListener('scroll', () => {
console.log('Inside Event Listener ' + this.readingZoneHeight);
//this.handleWindowScroll();
});
}
}
When I console log this is shows a Reading class with all the props it should readingZoneHeight, wordsPerMinute etc but this.readingZoneHeight is undefined, however inside the event listener this.readingHeight is the correct value so not sure whats happening here?
Anyone Help?
That happens because you are calling the Reading's processEvent method from the constructor of the ElementEvent. So this is actually called as part of the super(event) call in the constructor of the Reading class.
And since the super(event) happens before you actually assign anything to the this.readingZoneHeight it is undefined at the time you log it.

Call method overridden in child class, from the parent class [PHP -> JS]

In my Javascript there is a parent Base class that will be extended by others.
I'd like to:
define in it a method getSubject() that could be common to all children, when it is not overridden.
make getSubject() rely on a Base property, that eventually could be overridden as well.
always call the getSubject() method in the context of the caller (the children classes or the Base class)
To clarify (hopefully) what I want to do..
I wrote (non-valid) PHP code as an example.
<?php
class Base
{
const SUBJ_SELECTOR = 'input';
public function init()
{
$this->wrapper = ....;
$this->subject = $this->getSubj();
if ($this->subject.attr('data-active')) {
// ... do stuff
}
}
public function getSubj() // One definition in parent
{
return $this->wrapper.find(self::SUBJ_SELECTOR);
}
}
class Select extends Base
{
const SUBJ_SELECTOR = 'select' // Override just the selector
}
class Textarea extends Base
{
const SUBJ_SELECTOR = 'textarea[name=foo]';
public function getSubj() // Eventual overriding
{
$subjs = $this->wrapper.find(self::SUBJ_SELECTOR);
foreach ($subjs as $subj) {
if ($subj.attr('multiline')) {
return $subj;
}
}
return $subjs;
}
}
I'd like to achieve the same result with Javascript (and JQuery eventually).
Actually I wrote some code (that I still didn't test) as a sketch:
var Base = function() {
this.options = {};
this.subject_selector = 'input';
this.wrapper = $('.container');
};
Base.prototype.getSubject = function() {
return this.wrapper.find(this.subject_selector);
}
Base.prototype.init = function() {
subj = this.getSubject();
if(subj.attr('data-active')) {
// ... do stuff
}
}
var Select = function() {
this.subject_selector = 'select';
}
Select.prototype = new Base();
Select.prototype.constructor = Select;
var Textarea = function() {
this.subject_selector = 'textarea';
}
Textarea.prototype.getSubject = function() {
subjs = this.wrapper.find(this.subject_selector);
for (var i = subjs.length - 1; i >= 0; i--) {
if(subjs[i].attr('multiline')) {
return subjs[i];
}
};
return subjs;
}
Textarea.prototype = new Base();
Textarea.prototype.constructor = Textarea;
Would it work correctly? Is this a proper use of the inheritance model?
Am I callling the method in the right way and will I get the expected result when executing the init() method?

Categories