Correct way to extend Angular class - javascript

I'm working on an Angular (6) project and I'm trying to (elegantly) extend a Base Class for my containers. The app is really a "web tool" rather than a traditional "web app" (i.e. it follows a sequential order, rather than allowing the user to move around pages as they please).
If the user navigates on their own, I need the rendering container to check to see that all of its dependencies have been met (i.e. have all prior stages been completed?). If they haven't, I need to bring the user back to the earliest container that has all of it's dependents met.
Basically I made a Base Class that runs this check on initialization and manages any necessary redirect behavior. This all works as expected, but my issue is that the base class needs the StageGuard service (responsible for the aforementioned dependency check and redirect) passed to it through each container's constructor.
Considering I'll probably expand upon this base class to do more things that all containers will need, the need to pass items and services (other than unique properties associated with the container like, Stage Name) to the base class via the super() call.
I'm not sure how I'd get around this, only because the issue kind of makes sense -- the Base Class can't use the instances of services created because it's never a standalone instance itself. That said, you can probably understand why I'm plagued by a "there has to be a better way!" sensation.
Apologies if this is classical inheritance 101 and my googling is failing me, any insight is greatly appreciated.

Related

Should Protractor Page Objects expose ElementFinder

There is a discussion in our team if we should forbid exposing "ElementFinder" and "ElementArrayFinder" in our Page Objects.
The main reason is following quote by Simon Stewart. Page Objects Done Right - selenium conference 2014 (page.7)
If you have a WebDriver APIs in your test methods... You're doing it wrong.
SeleniumHQ/selenium/PageObjects https://github.com/SeleniumHQ/selenium/wiki/PageObjects
The approach is correct for transition functions that returns another Page Object or if multiple selections are happening on one Page so we can return Page and chain these calls.
But when we are doing something really simple there is a lot of boilerplate to write to test that element exist and have text.
Creating those mimic functions of "ElementFinder" does not make much sense to me.
Most of the time its faster and more readable to expose element and use build-in functions of "ElementFinder" like ".getText()". Do you think its better make element private and expose only "getElementText()" function?
What is best practice do you forbid to expose "ElementFinder" and "ElementArrayFinder" in Page Objects?
We use cucumber so tests are divided between
features
step definitions
helpers
page files
All the logic and asserts are in step definitions and helpers. The step definitions invoke page methods when a screen value is needed. The page methods return POJOs. All details about finding elements are encapsulated in the page files. The reasons are obvious; when (not if) the page HTML changes you only have to make the fix in one place. Once you break encapsulation you have the start of a maintenance nightmare.
A pattern that I often use is to create a helper class e.g. OfficeInfo, to contain, say, all the td's in a tr for a table of offices. The page method would return
List<OfficeInfo>
i.e. one list element for each tr. The office information is now decoupled from the details of how that information is displayed on the page. If new td's are added you update class OfficeInfo, update the page method and insert the new step definition without impacting all the other places that OfficeInfo (but not the new td) is used.

Controller.doInit is not a function?

In my application, we have a panel of back, next buttons that are included in every screen for navigation. From the next button, I want to call a Controller using:
myApp.app.getController('folder.MyInfoController').submitMyInfoForm(nextButtonId);
However, I get a TypeError: controller.doInit is not a function. I have an init method in my controller which is already working.
You are getting this error simply because "folder.MyInfoController" is not a controller - that is to say, it does not extend Ext.app.Controller which Ext.app.Application::getController is expecting to find. Now for some bonus points...
My psychic senses are telling me that in all likelihood you are trying to find a view-controller - which is notably not the same as an application-controller. They both share a base class but serve different purposes and ultimately have different implementations. This is well defined in the API.
As a preface to the next paragraph, I'd also point out that what you are doing looks like an anti-pattern. The biggest advantage of using the view-controllers is that they afford you all the conveniences of MVC whilst keeping your components decoupled from each another - there are only specific cases where you can justifying accessing one outside of the component scope and I can't think of any good reason why you'd need to access one from a global context.
That said, you can find a view-controller by obtaining a reference to the instantiated component (of type "folder.MyInfo" - or whatever you've called it) and asking it for it's view-controller. Note that there is a 1:1 relationship between a component and it's view-controller - each instance of the former has a unique instance of the latter.

ExtJS MVC conventions, naming and behavior

Lately (2.x / 3.x) I just used xtype & factory methods to receive a instance of a class which was as simply as fast. Now I have started 4.x and my first App with MVC. As described in the tutorial the MVC pattern requires me to extend a class for each view I wan't to use, even if I use it just one time. But the best practice written by Sencha itself says:
just extend for re-useability or adding of functionality
In my case I need to register a whole bunch of classes even if they could be created from one base class except of some params like title, width,...
Another point is that the Controller overwrites any StoreId by convention and also requires a strict typing, means the class-name must end with an s. But as far as I know I cannot spare neither the model nor the store within the the controller store/model-array so is there any other point for this convention cause it seems not to spare typing.
Next point is that after merging from 3.X to 4.X the application initial load time has extended which seems to be caused due to either the many new classes that need to get defined or due to the fact that all controllers get instantiated at startup due to the default behavior of the MVC pattern. Is there any way to not auto instantiate a controller and just doing it lazy, for example when I request it on the application controller?
Yes I know, that are a bunch of questions but I guess they all around the same topic.
EDIT
After some sourcecode-digging I am no longer sure about the
requirement of the s when naming a store. I thought I stumbled over
this while going through the MVC tutorial. Can anyone verify this?
EDIT 2
My conclusions
Lacy rendering is quite simple. First of all the Controller should not be mentioned in the ApplicationController controller array. To create a instance of such a controller use the ApplicationController.getController(pureClassName)
[Note that each controller contains a reference to the ApplicationController called application] Now you need to be aware of the fact that the init(application) method and the onLaunch(application) method get no longer invoked by the ApplicationController, you need to do this yourself. When calling getController() the ApplicationController first lookup if there is already a instance of this controller in the internal reference cache if not it creates a instance and inject the controllername as Id. So controllers are a sort of singleton which is perfectly fine.
The controller itself creates all the getter for the registered stores, models and views and, that's a guess, it instantiate them (at least the stores)
About naming restrictions for stores, there no restrictions about ending with an s.
These are very valid points.
First, it has to be mentioned that you don't have to use MVC with ExtJS 4. You can still use ExtJS 3 style in your code.
I assume that if you understand the advantages of MVC and decide to adapt it, then yes - you will have to extend classes and there is some overhead, but admittedly you will end up with a cleaner, more reusable code. It has to be said that while you need to extend top-level views, the items within them can still be coded old style. In addition to this, within the init() of the controller you can modify certain view configs (which allows less of class extension, but more controller code).
I have to admit that if you have experience with ExtJS 3 and you're migrating to MVC style of an app, you will eventually see that the benefits outweigh the work involved.
Personally it's the first time I've been made aware of this 's' business with stores. So I can't comment much on this.
Lastly, a properly-written ExtJs 4 app, one that makes use of dynamic loading should load faster than an ExtJS 3 app. You can also compile an Ext version that only includes code used in your app. And yes, you can instantiate controllers (and their views and stores) when you need them, which works like a charm:
loadPage: function(aControllerName)
{
// save recent page in a cookie
Ext.util.Cookies.set('RecentPage', aControllerName);
// Dynamically load the controller
var iController = this.getController(aControllerName);
// Manually initialise it
iController.init();
// Load the page (by getting the first view of the controller).
var iPage = this.getView(iController.views[0]).create();
// Add the page to the content panel.
var iContentPanel = this.getContentPanel();
iContentPanel.removeAll(true);
iContentPanel.add(iPage);
iContentPanel.doLayout();
}
1.Izhaki answered your question well about the lazy controller initialization.
2.I am not really following you on the gripe about Store names. There are no restrictions on store names. They are merely suggestions of naming conventions.
3.The Ext.define method is great to define your classes - similar to Java or other OO languages. This is NOT required however and you can simply use Ext.create method to create an instance of a framework component and pass it custom config object.
You can also use Ext.define to create you base class and then call Ext.create('MyBaseClass',{title:'mynew tile'}); to get a slightly modified version of your base class.
I encourage you to read through the Sencha guides on MVC, and Class system and also review their examples to get better understanding.

On using mixins in a CoffeeScript game engine

I am working on a CoffeeScript game engine for Html5 canvas. I came up with the "cool" idea to utilize mixins after I checked a very neat CoffeeScript implementation. I thought, it may be a very cool idea to reduce the various hierarchy of objects that game objects usually provide, by developing a set of mixin-based components, each of which has a very specific functionality. Then, when developing an actual game, one could build unique game objects on the fly by basically starting from one component and mixing it with a bunch of other components. This reduces the hierarchies and allows for frequent changes.
Then I thought about the possible collisions that might come up, for example having a few components define a method with the same signature. Now, I am not as excited as before.
What should I do? Is this a good way? I still like it, especially because of JS' underlying prototype mechanism, which allows for such an easy way to combine stuff on the fly.
You're talking about an entity component system. There are a couple written in JS; the most popular is Crafty, which is big but worth looking at. I recently wrote one in CoffeeScript (just for funsies; will probably never release it).
A few notes about collisions:
So first, the problem may be worse than you think: collisions will happen if two methods have the same name; JS doesn't differentiate function signatures. It also might not be so bad: why don't you just create a namespacing convention, where each behavior (meaning method) is named after the component it belongs to, like burnable_burn?
To take a step back though, mixins aren't the only way to build this - behaviors (i.e. things a component can do) don't have to be methods at all. The motivating question I ask is, how do you trigger a behavior? For example, you might do:
if entity.hasComponent "burnable" #hasComponent provided by your framework
entity.burn()
But that doesn't sound right to me; it creates a weird coupling between what's happening in your game and what components you have, and it's awkward to check if your entities implement the relevant component. Instead, I'd like behaviors to be listeners on events:
entity.send("applySeriousHeat") #triggers whatever behaviors are there
And then have your component do whatever it needs to do. So when you add a component to an entity, it registers listeners to events. Maybe it looks like (just sketching):
register: (entity) -> #called when you add a component to an entity
entity.listen "applySeriousHeat", -> #thing I do when this event is sent to me
#do burnination here
To bring that point home, if you do that, you don't care about collisions, because your behaviors don't have names. In fact, you want "collisions"; you want the ability to have more than one component respond to the same event. Maybe it burns and melts at the same time?
In practice, I used both setups together. I made entity.addComponent mix in the component's functions, since it's occasionally convenient to just call a behavior as a method. But mostly, the components declare listeners that call those methods, which helped with decoupling and reduced the awkwardness of having to use scoped names, since I don't call them directly in most cases.

How to limit access to a javascript object?

I was watching a video on making a good javascript application infrastructure. Basically what it said was:
Your application consists of components
Components are parts of the page that can act on their own.
components can be registered into te application.
upon registration, they get their own sandbox.
A sandbox is an component's interface to the application core.
The core is built on top of a javascript library.
Components only have access to their sandbox, not to other components, nore the core or the underlying library.
Now, what I'd like to make is an application where you can easily make new components. Components have their own part on tha page, their own div in which they can work. And here comes the first part of my question: I want to give these components a copy of the jQuery object, but that has an internal restriction applied so that it can only work inside a certain containing element.
The second part is,that even if a component has limited access to the DOM using jquery, it can still access the document. I have tried both setting Window and Document to null, before running my test script, but the browser doesn't allow this. Is there any way that I can truly restrict the possibilities of an object to the methods of 1 object that I pass to it?
You're mis-understanding the point here. The intention isn't "make it 100% imposible for a component to acces anything it shouldn't". The ONLY way to do that is the insanely complicated step that Facebook took which is to parse the JS/HTML code and re-write it to dis-allow certain references, etc. I'm betting it took their dev team 1,000+ hours to do and there are still holes in it.
Basically the intention is to give each component a sandbox to play with and then say "please only use this". The authors then comply with the request.
Your sole other option is iFrames, in which case a component can do whatever it wants and it won't effect anything (assuming you're on a different sub-domain and you provide a parent-window proxy).

Categories

Resources