In Ember.js on an ObjectController there is a function init() which fires when the controller is instantiated. Is there a way I can fire some additional code, when the controller leaves context?
Here is what I am doing in the init():
init: function() {
jQuery("body").css("background-color", "#f2f1ec");
}
On the controller exit, or lose context I want to simply change the background color again:
jQuery("body").css("background-color", "#333333");
Thanks.
I would create a custom view and write make the css changes on didInsertElement instead of handling it in the controller. In this particular case, since you're operating on the body element, you might even be able to get away with doing it in the activate and deactivate functions of the route you're looking to target. (It might be a problem if you're doing it on ApplicationRoute though. Not sure if that is entered before are after document.ready()
Here's a fiddle using the Router's activate and deactivate functions.
And here's an example of the custom view.
Related
Currently using ExtJS 4 and I am trying to use the controller for implementing all events but there are some events that i am handling in the Window itself which are the close and destroy events. I need to execute some code here.
Is this bad practice ? If the events happen in the Window (an instance of Ext.window.Window).
Should I but forwarding these events to the controller to handle ?
I am unsure the correct way of doing this but I presume I would have to get a reference to the controller from my "window" in it's event and then call fireEvent on the controller?
What is the best practice here?
I am using ExtJS 4.2 so cannot use MVVM.
ExtJS seems to let me implement the events directly in "Components" but following the MVC pattern, is this not bad practice and everything should really pass through the controller.
The controller or viewport should handle the event.
You don't need a reference to the controller inside the window.
If you want custom events, you need to fire the event from inside the window like:
this.fireEvent("myCustomEvent"[,elementThatTriggeredTheEvent]);
Then you then need to listen to the event inside the controller using a reference to the window:
yourWindow.on("myCustomEvent",this.myCustomEventHandler[,scope]);
There are also ways to listen to events without having a reference to the event triggering element.
Edit- Regarding your comment:
If you need to do stuff on afterlayout regarding elements inside the window, then i would do it inside the window. If you want to do stuff to elements that are not defined inside the window, then let the controller, that instantiated the elements, handle it. In ExtJS 5 there is something called a ViewController. I don't know if it's already in 4.2. You could utilize the ViewController to split the stuff that happens in your window. Here is a link on that:
https://www.sencha.com/blog/using-viewcontrollers-in-ext-js-5/
EDIT 2:
If you don't want custom events, just listen with the controller to the events the window already throws on important occasions.
I would like to create a directive that is similar to a control. It should be able to be instantiated from "anywhere" and I want to call functions on it's scope from a parent scope/controller.
A very easy example would be:
I have a special directive called myContactForm (which can be used in different places and pages). Now this myContactForm, in it's templace, uses the directive myEditControl. myEditControl is, when you look at the template nothing but an input and a button and in the scope has the function "clear()" so you can delete whatever is inside the input and maybe other functions.
Now when something happens in myContactForm (for example a button is pressed or a broadcast is received or whatever) I want to call "clear()" on the myEditControl that's inside it. Just like it was a normal control.
How would that be done?
I know about the require but that only works for parents and I would have to know the Controllername of the Directive that uses myEditControl. Instead I want any View/Controller to be able to use myEditControl. And I cannot require the myEditControl-Controller from myContactForm because it is a child not a parent.
What is the technique used in angular to solve these kind of problems?
My idea was to transmit a callback or "myContactForm"-Scope to the myEditControl with an attribute so the myEditControl can "register" itself on the parent and the parent then saves that controls scope for later reference and calling of functions. This seems very hacky though....
I'm playing a bit with Backbone.js and Backbone.Marionette and I would like to know what's the difference between trigger and triggerMethod.
In particular, is there any rule of thumb to decide when use the former or the latter?
In my mind events, for example, are useful to communicate between a DOM element and its view.
triggerMethod is used in Marionette to update in cascade different components, e.g. a layout calls the show method to its children (children respond to onShow). So, for me its the same as calling a direct method on it. Is this true?
What about trigger?
Thanks you in advance.
There isn't a huge difference, and it simply depends on what you want to do...
trigger will trigger an event
triggerMethod will trigger an event AND call a corresponding method according to naming convention (see https://marionettejs.com/docs/v2.1.0/marionette.functions.html#marionettetriggermethod)
Obviously, if you only want to trigger an event, you'd use trigger. But using trigger you also create a "home made" triggerMethod implementation: trigger the event, then have a listener that will call the function you want.
So what about triggerMethod ? As mentioned above, it will trigger an event and call a method. So if your only objective is to call the method in the first place, there isn't necessarily a need for using triggerMethod.
So why would one use triggerMethod at all? Because it gives you "hooks" to add functionality with event listeners. In my book on Marionette, for example, there is a triggerMethod call in https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/edit/edit_controller.js#L24 to display error messages on a form. The same could be achieved by simply calling
view.onFormDataInvalid(contact.validationError);
But as mentioned above, triggerMethod give us a "hook" for later use. For example, let's say I want to add logging of user errors: I can simply add a listener to my view:
initialize: function(){
this.on("form:data:invalid", function(validationError){
// log error here
}
}
This additonal functionality can be added without impacting the rest of the code, because we've used triggerMethod instead of a direct method call. In addition, it will be easier to test later (small tests, with single point of failure):
test that "form:data:invalid" event is triggered when a user enters incorrect info
test that when "form:data:invalid" event is triggered, error gets logged
etc.
trigger(name)
Part of Backbone.js
Triggers event using the name passed in
triggerMethod(name)
Part of Marionnete.js
Does everything trigger(name) does
Also calls methods using a predefined naming convention.
eg. triggerMethod('foo') will call onFoo()
eg. triggerMethod('foo:bar') will call onFooBar()
I'm making a charting application that allows you to create graphs using a drag and drop interface.
I have highcharts and I'm using the highcharts-ng directive.
This directive watches the title, options, and series. And when a person makes a change, I process them and make changes to the options object. Then highcharts-ng redraws the chart.
The problem I'm finding is that I change a few properties in a row such as options.xAxis and options.yAxis, and whenever I do this the application is lagging a bit because it's launching a redraw for every change.
So what would be the angular way to approach this, while still being efficient?
A potential solution I thought of was to add a flag to the highcharts-ng directive, and have it trigger whenever it's changed. And then just change it after I'm done processing the data. Another potential solution is to listen for a certain event inside the highchart-ng directive, and then trigger the redraw whenever that event is received. But these solutions seem/feel a bit hacky to me.
Angular does its own dirty checking and (ideally always, not but really) rewrites the Angular-controlled sections of the DOM whenever their corresponding view models change. I think that this behaviour is so fundamental to Angular that if you don't like it, you'd either better work around it, or use a different databinding framework.
The workaround I'd recommend is basically what you described in your first option: a view model inside the view model. Have a private variable inside the directive's scope which tracks the changes you're interested in, the ones which happen more frequently than you want to redraw. Then when you're ready to redraw (you'll need your own logic for what determines "ready"...time? a particular kind of change? a particular threshold of change?), update the real view model by setting your private variable back to its original field on the real view model.
Code sketch:
// (inside the directive)
var _options = $scope.options;
// ...
// rapidfire updates happen; save them to _options rather than $scope.options
// ...
// now you're ready to redraw:
$scope.options = _options; // angular now knows $scope is dirty and triggers the redraw
I've assembled a modestly sized application and I am in the process of factoring code to reduce the overall number of maintained lines, as well as performance tuning. The use case that has me posting this question is that I have a button embedded in a menu that invokes (or needs to invoke) a method on a controller that displays a form. This currently is implemented using a direct reference to the specific button control, creating a panel, and putting that panel inside of my viewport.
The question at: ExtJS 4.1 Call One Controller From Another begins to address the issue of best-practices near the end of responses, but doesn't really settle on a base-case that can be reproduced or extended to cover more complex implementations (which is the aim of my question.)
Given the two controllers:
A "main menu" controller.
// controller/Menu.js
Ext.define("App.controller.Menu", {
extend: "Ext.app.Controller",
init: function () {
this.control({
"viewport > mainmenu > button": function (ctl, evt) {
}
});
}
});
A user account controller
// controller/User.js
Ext.define("App.controller.User", {
extend: "Ext.app.Controller",
stores: ["User"],
views: ["user.Edit", "user.List"],
init: function () {
}
});
The Question
What would be the (best) way to implement a crosswise connection between the two controllers to properly delegate the responsibility of responding to a click event on the menu button for "Create a New Account?"
One Possible Solution
Using componentquery I can easily narrow down the focus of the button in the main menu view using a tag property such that the User controller is responding directly to the event:
// controller/User.js
"viewport > mainmenu > button [tag=user.create]": function () {}
An unknown alternative
Or I could possible winnow my way through the object graph to find the reference to the User controller from the Menu controller and invoke it that way.
// controller/Menu.js
// switch on tag case "user.create"
App.controller.User.createUserForm()
The real question
The question that results from all of this is what the "most acceptable" solution is here. One could imagine the use of a third, mediating controller, to "route" requests from controls to controllers but I think that goes against what the remainder of the framework is attempting to do. Using a variation of either of these methods currently works however neither feels completely clean and reliable; or ultimately maintainable long-term (as code gets spread out rather quickly.) Additionally the thought had occurred to us to drop into raw events but we run into the same kind of maintainability issues there.
Some short lines:
A thing that I don't understand is that Sencha Touch has routing but no eventbus where ExtJS has a event bus but no routing... (and there are more points where the MVC implementation differ) Whatsoever, because I am using ExtJS most of the time I created a custom routing to fill this gap for me. Maybe sencha will add this in version 5.
The easiest and quickest solution: use the getController() of the Ext.app.Application controller to invoke the responsible controller from your menu controller.
The (imo) best solution: write yourself a router where each controller register it's routes to and use both; routing and eventbus. This gets really handy if your app have shared components that are used by more than one dev team.