How do I override Backbone.Router.execute function in its coffeescript child class? - backbone.js

I have a class which is extending Backbone.Router using the extends keyword in coffeescript. How can I override the Backbone.Router.execute method in my class?
I tried adding a execute in my child class with the same method signature but it's still calling the parent class method instead of my custom method.
jQuery ->
class MyRouter extends Backbone.Router
routes:
"path/:id" : "myFunction"
execute: (callback, args, name) ->
console.log('hello')
console.log(args)
# do stuff
args.push(parseQueryString(args.pop()));
if callback
callback.apply(#, args);
myFunction: (id) ->
# do stuff
I want to add some checks on args before myFunction gets called but somehow not able to override the execute method. What am I doing wrong here?

It looks like you simply cannot mix backbone's objects and ES6 classes.
Here is a post which explains it in great detail.
it turns out that ES6 classes don’t support adding properties directly to the class instance, only functions/methods. This makes sense when you understand what is actually happening. With JavaScript inheritance, properties are generally meant to be set on an instance when its created, while methods are set on the prototype object and shared between every instance. If properties are added to the prototype directly they will also get shared between every instance, creating problems if the property is an object with mutable state like an array
You will have to stick to the backbone way of using Object.extends(). Here is an example for your code in coffeescript:
MyRouter = Backbone.Router.extend
routes:
"path/:id" : "myFunction"
execute: (callback, args, name) ->
console.log('hello')
console.log(args)
# do stuff
args.push(parseQueryString(args.pop()));
if callback
callback.apply(#, args);
myFunction: (id) ->
# do stuff

Related

Where is the correct place to put event handlers in class components that have constructors?

I'm implementing a solution to a recent question I asked on here. However in order to make the logic work I must use a function. When I place the function below the constructor I get an error as shown below:
If I can't place it in the constructor, or the render method where is the correct place to put handler functions?
Consider This:
loginGetHandler() {
//...
}
If you use this declaration for your function, don't forget to bind it in the constructor as:
constructor(){
//....
this.loginGetHandler = this.loginGetHandler.bind(this);
}
Or as ES6 Named Arrow Function:
loginGetHandler = () => {
//...
}
You will be needing no binding here as ES6 already does that for you.

Binding in React: What does `this` refer to if I don't bind?

I had some problems to understand the whole this issue in React (or JS in general) and found this very helpful article:
https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56
However, there is one basic thing that I'm still not sure about.
Let's take the Approach 2 as an example:
// Approach 2: Bind in Render
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage.bind(this)} />
);
}
}
Now, let's look at the wrong version of this code where we just do not do the binding that is required in order to refer to the right this (the HelloWorld component):
// Wrong "naive" version of the code
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
My question is very simple: In that wrong version, it is my understanding that the this in console.log(this.state.message) within the logMessage function does not refer to the HelloWorld class object anymore. What does it refer to instead? Thank you!
EDIT: Turns out my understanding is wrong. This is not the this that does not work anymore. It's "the other" this at onClick={this.logMessage}! The reason will be given in the answers below - just wanted to correct this right here in the question.
Whenever you call a function using - (), the function context - this is set automatically based on whatever goes before ().
For example,
let A = {
foo() {
console.log(this === A);
}
};
when you call foo like this -
A.foo() // prints true
the context function foo receives depends on A.foo, here it is A. But when you call the SAME function using a different member - for example -
let B = {
foo: A.foo
};
B.foo(); // prints false
Even though you're still calling the exact same function, the function/method foo receives a different context (here B) -
And sometimes, you can force the context of a function using one of these three things -
1. .bind
Docs: MDN
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
2. .call, .apply
Both of them call the function with a given this value.
Docs: MDN Function.prototype.call
Docs: MDN Function.prototype.apply
3. Arrow function
Docs: MDN Arrow functions
class
JavaScript class methods have the same concepts -
class A {
foo() {
console.log(this instanceof A);
}
}
let a = new A();
a.foo(); // prints true
and when you run the experiment of assigning this function to a different method of a different object,
let b = {
foo: a.foo
};
b.foo(); // prints false
Whenever you pass a function somewhere else, you're not passing the context along with it, but you're expecting some context inside your function by using this and
The source of the issue
In your example,
<input type="button" value="Log" onClick={this.logMessage} />
specifically,
onClick={this.logMessage}
which is analogous to the above example -
let b = {
foo: a.foo
};
So, now, whoever calls your function using b.foo (here React) needs to know the context. So you have to set the context for the function before you pass it to onClick
What does it refer to instead if you don't bind?
In strict mode, the following happens -
Thus for a strict mode function, the specified this is not boxed into an object, and if unspecified, this will be undefined
Source: MDN under the section "Securing JavaScript"
And in all of the above examples with b.foo, if you assign it to a variable instead of object property,
let c = a.foo;
c(); // this will be undefined in foo
So, in your logMessage method, the value of this will be undefined.
this always refers to your class' attributes and behaviors but you have to bind this to the functions in which you want to use those attributes and behaviors. If you do not bind class level this with a function so "this" in that function refers to the attributes within the context of that function only.
You can also bind this in component cycle's callbacks like componentWillMount, constructor or anywhere where this has the reference to the class.
Forexampe:
componentWillMount(){
this.anyCallBack = this.anyCallBack.bind(this);
}
anycallBack(){
//now this will refer to the class
console.log(this);
}
The default value of 'this' depends on which event you are binding to. With JavaScript, in general, DOM events, such as onClick or onChange have 'this' as a pointer to the DOM element that triggered the event. For instance, if you were to create a button and attach a click listener, and in that listener, use console.log(this) you will see the button is the value of this.
Note: React has 'this' set as undefined by default.
Event handlers for setTimeout and setInterval, will set 'this' as a pointer to the window object.
There is an inherit danger to using bind. Each time you bind to a method, JavaScript creates a new method. The new method is an anonymous method unless you set it's value to a property or variable:
let myBoundMethod = myMethod.bind(this);
If you need to detach an event from a DOM element, unless you have a reference to the bound method, you will not be able to remove the event listener from the event. This can be a source of memory leaks in your application. Always use your debugging tools to monitor memory usage. It is normal for it to go up and down, but it should have a relatively stable baseline.
DOM elements removed from the DOM will often garbage collect along with their event listeners, but if there is still a reference in memory to the element, it will not be garbage collected.

Use dependency in base class without having to pass this dependency from inheriting class [duplicate]

This question already has answers here:
How to extend a component with dependency injection?
(4 answers)
Closed 6 years ago.
In my quest to learn Angular2, i came across the following situation:
1 base class, which uses the angular2/http dependency
1 inheriting class which extends the base class
How can I inject the angular2/http dependency in the base class's constructor, without having to pass http as a parameter when instantiating the inheriting class.
I don't use http in the inheriting class, so I don't want to see it there!
For example
// base class
class CRUDService {
// http is used in this service, so I need to inject it here
constructor(#Inject(Http) http) {}
findAll() {
return this.http.get('http://some.api.com/api/some-model');
}
}
// inheriting class
class ThingService extends CRUDService {
constructor() {
// because we extend the base class, we need to call super()
// this will fail since it expects http as a parameter
// BUT i don't use http in this class, I don't want to inject it here
super();
}
}
Ideally, I would just create a new http instance in the base class and use that like so let http = new Http();, but that obviously doesn't work.
That's not supported. If you want inject something you have to list it in the constructor of the sub-class and if you want to pass it to the super-class you can by using super(someDependency). There is no way around.
That's not an Angular limitation but a language limitation that is quite common among typed classes.

CakePHP - centralizing controller logic

Using CakePHP, I am finding that I'm duplicating some code between controller actions. I have a dozen or so actions (belonging to various controllers) that all need to run the same query and set() the same 10 variables for the use in a particular layout. They also need to handle any errors in the same way and render an error page.
I know that components are intended to centralize logic used among controllers, but in my case, this logic needs access to the set() and render() methods of the controller. What is the suggested approach to this situation?
Thanks, Brian
Put the logic in your AppController class which your controller should extend from.
Check out the docs: http://book.cakephp.org/view/957/The-App-Controller
Ended up rolling my own sort of business logic layer on this one. Example below. Thoughts/comments welcome.
class MyController extends AppController {
public function my_action() {
// The BLL class is specific for this action and gets the entire
// controller so has access to the set() method as well as components.
$this->Bll = new MyActionLogic($this);
$this->Bll->do_whatever();
}
}

CakePHP: Layout, variables and question

I got layout, nothing special, three columns, just to learn CakePHP. In documentation I found nothing about this case.
I got some statistics in sidebars, si I send them to layout file (default.ctp) cause they are displayed on every page.
I build (thanks to one user here) a component:
class SidebarComponent extends object {
function startup(&$controller) {
$this->controller = $controller; // Stores reference Controller in the component
}
function count_articles() {
$articles = ClassRegistry::init('Articles')->count_articles();
$this->controller->set(compact('articles'));
}
}
Everything is working perfectly. I got question about my technique. I needed to load component method in controller by putting:
$this->Sidebar->count_articles();
So I decided to make it a bit shorter, cause I will have to put it in every controller. So, I created new component's function:
function sidebars($userid) {
return array(
$this->top_articles(),
$this->random_article()
);
}
And I initialize it in controller that way:
$this->Sidebar->sidebars();
Everything is working correctly, I need only advice/feedback if it's good way I do this :)
Thanks for your time.
you don't need to call it explicitly in every controller. component's startup() method is called automatically before every action in the controller that is using your component.
so you can use startup() to get and set your data for views, and if you need some initialization before (like getting reference to controller), put it in component's initialize() method.
If you have sidebars with the same things in them, also sounds like a case for elements as well

Resources