I have a set of functions shared between all my controllers and I'm doubting whether I should place them in a component, loaded from every controller (or from AppController), or add them in the AppController class (with visibility set to protected), so all the controllers inherit them.
Which is the better?
Creating a component is recommended, IMO. Components are lazy loaded and also help keep your code look clean. Also in use cases where you need access to some sort of model data, you DO NOT want to load models and call them from AppController!
Related
Working with Angular 1.5, and given a component hierarchy such as:
compA
compB
compC
Is there a better way to bubble events from nested child components to the interested parent component?
The two options I see are:
Call $scope.$emit() from compC. Use $scope.$on() in compA.
Pros
compC is decoupled and more likely to be re-usable
compB does not have to be made aware of this output in any way
Cons
Use of $scope, which I was hoping to avoid since it no longer exists in NG2. However, I'm not finding a better solution.
Pass callback from compA to compB and then to compC using a & binding
Pros
compC is decoupled and more likely to be re-usable
Cons
compB has to be involved, making this solution fragile
Maybe I should make an exception and allow $scope use for this scenario. Or, there is the option of emitting/listening on $rootScope instead.
EDIT: I'm finding $rootScope should be used only for truly global events, and it's common to forget to clean up your listeners, which is done automatically on $scope.
One more way of passing data from CompC to CompA (or in between any components) would be to use a service instead of event based message passing. You could define dependency in all the components on a service and use that service to pass data amongs them. This would again make the components reusable.
I'm creating a simple page using a CompositeView from Marionette, with a parent lodash template that wraps a group of templates: one for each item in its Collection.
The page displays properly, and each ItemView renders properly with it's own child template, but binding a 'click' event fails to register anywhere in the application, even if moved into the CompositeView.
I have my suspicions that this is happening due to the events being bound before the element is created, and it not updating afterwards. From what I have read, it uses / used .live() / .on(), but I can't see any other reason that it wouldn't register.
Is there a way to make sure that events are rebound with onRender()? Am I doing something else wrong entirely?
Environment: RequireJS, BabelJS (es6), Backbone 1.1.2, Marionette 2.4.1, jQuery 1.10.2
I've created a gist of the code in question.
Non ES6: Try assigning this.events before the parent constructor call, in Backbone 1.2.1+ the events are created BEFORE initialize in the parent constructor. In 1.1.2 they are created AFTER initialize, but still as the last thing the parent constructor does - so you should either assign them in initialize, or do it before the super call (I recommend before super call in the constructor so that if you upgrade it doesn't break again).
In ES6 you can't use this before the super call.
You could call this.delegateEvents(); again, but it's not ideal as it stops listening and then re-listening to any existing events which is less efficient (though the impact is probably negligible).
You can use es7's static property on the class definition if you are using a transpiler that supports it (e.g. Babel), or make events a function which returns an object if you need it to be dynamic.
How do you create a ReactJS component that reaches multiple levels up the component/DOM hierarchy?
A good example of this is a Modal. I want to trigger and control the modal from a child nested way down in my app, but a Modal requires that the DOM be much higher, most likely all the way up as a child of the document body.
I'm considering a "portal" pattern, as described here: https://github.com/ryanflorence/react-training/blob/gh-pages/lessons/05-wrapping-dom-libs.md#portals
FakeRainBrigand even wraps the pattern up nicely in a mixing in this post: https://stackoverflow.com/a/26789089/586181
This feels like a hack to me. Great if you want to use a non-react library like jquery-ui, but without that need breaking out of react just to render a react component somewhere else in the DOM seems like overkill. Is there a more "React" way of achieving this?
Thanks
I'll leave this best to the react documentation. If you must have buried React elements that need to communicate with other elements outside of their Parent Child or possibly even grandparent than see the below.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
https://facebook.github.io/react/tips/communicate-between-components.html
I've written a library to help with this. I avoid the DOM insertion hacks used by Portal strategies out there and instead make use of context based registries to pass along components from a source to a target.
My implementation makes use of the standard React render cycles. The components that you teleport/inject/transport don't cause a double render cycle on the target - everything happens synchronously.
The API is also structured in a manner to discourage the use of magic strings in your code to define the source/target. Instead you are required to explicitly create and decorate components that will be used as the target (Injectable) and the source (Injector). As this sort of thing is generally considered quite magical I think explicit Component representation (requiring direct imports and usage) may help alleviate confusion on where a Component is being injected.
You can completely use my library to bind a ModalComponent to a root level component that you decorate with the Injectable helper. I plan on adding an example of this use case soon. It even supports natural props pass throughs, and all the various component types i.e. stateless/class.
See https://github.com/ctrlplusb/react-injectables for more info.
In my Backbone.js project I have one Model and several Views. All Views have registered callbacks for 'change:currentTextTitle' on this model:
// 'this' stands for any of the Views here
myModel.on('change:currentTextTitle', this.render, this);
Now a user performs some action, which causes the specific View to change its "current text title" field. This specific view then calls myModel.set("currentTextField", newTextValue) which in turn triggers the 'change:currentTextTitle' event calling all Views (including the one from which set() originated). Then all Views call their render callback functions.
The problem is that the render method is also called on the View from which the set()-Method was originally called, which is completely unnecessary because it is already up-to-date with currentTextTitle.
How would my Views call myModel.set() in a way that the other Views' callbacks get informed, but without triggering/calling the "source View" itself?
One workaround seems to be to pass the source view as part of the options parameter of the set() method (which gets passed along to trigger() and then along the the render() callback):
myModel.set("currentTextField", newTextValue, thisViewSetAttribute)
Then in the render callback one could check if thisViewSetAttribute != this. However, instead of implementing checks in every callback, I think it would make more sense to handle this in the Model itself by only calling the necessary callbacks and ignoring the source View from which the set() method call originated. Is this possible?
I think the 'proper' MCV solution is that your views should not know or care how the model changed, they should simply handle the change and update accordingly. If they are already current, the user shouldn't know the difference.
I definitely would not pass the source view to the model. Instead when the model changes, you could just have the view check if it is current and not re-render. But if the extra render doesn't cause any issues then just let it happen :)
In Backbone, the 'view' is both view and controller. So try to treat the change as 2 separate steps. First, convert user input into changes on the model, then as a separate step (initiated by model change event), handle that change and update the view. If each view does this, no matter how the model changes, everything will stay up-to-date.
I have extended class A in class B and i want to use class A methods in class b.
To share a method between two controllers, place the function in AppController.
To share a group of method related to a single feature, create a new component and use it in both controllers. It's the proper OOP way to do it.