How to efficiently reuse Ionic page against different providers? - ionic-framework

I'm working with Ionic 2 and I have entity management page which is suitable for different data providers.
Now I have page for character management.
export class CharacterListPage{
currentItems: Character[];
constructor(public provider: Characters) {
this.currentItems = this.provider.query();
}
// other stuff
}
I need to do creature management. Creatures structure is identical to character structure.
Obvious way is just copy-paste page and make some renaming:
export class CreatureListPage{
currentItems: Character[];
constructor(public provider: Creatures) {
this.currentItems = this.provider.query();
}
// other stuff
}
Is it possible to use more efficient way?

That looks like a typical use case for an abstract class, luckily typescript brings that feature to the .js world:
You have a base class, lets call it ListPage, which holds all the common functionality of a Character and a Creature which can then be extended by other pages and reuse this existing functionality:
class ListPage {
listItems: Character[] | Creature[];
constructor(provider: Characters | Creatures) {
this.listItems = provider.query();
}
// other common methods
}
class CharacterListPage extends ListPage {
constructor(provider: Characters) {
super(provider);
}
}
class CreatureListPage extends ListPage {
constructor(provider: Creatures) {
super(provider);
}
}
For this minimal example it may not seem very efficient but when your classes get more complex and have much common functionality it will be very useful.
Here you can find the documentation on typescript classes.

Related

How to Inherited multiple class from different model in Flutter

I have Card Model and it have three different classes in there, App, Figures and Item.
I have another model called Favorite Model which is going have similar classes like Card Model but there will be just extra 2 variable.
I'm trying not to copy the whole classes and paste it inside Favorite Model because it'll look like duplicated so I'm just trying to texted it from Favorite Model but some reason I'm not allow to extends only one class but not three.
Card Model
class App {
String name;
int id;
bool showCards = false;
List<Item> items;
}
class Figures {
}
class Item {
}
Favorite Model
class Favorite extends InheritedModel<App, Figures, Item>{
}
I'm getting this error so just wondering if there is a way to declare 3 paremeters.
The type 'InheritedModel' is declared with 1 type parameters, but 3 type arguments were given.
Try adjusting the number of type arguments to match the number of type parameters.da
I'm not really sure the way I'm trying to do is logically correct so let me know and correct me.
I'm likely not understanding how your model hierarchy is set up, but maybe you could try some composition, such as:
class CardModel {
App app;
Figures figures;
Item item;
}
class FavoriteModel {
App app;
Figures figures;
}
class InheritedCard extends InheritedModel<CardModel> {}
class InheritedFavorite extends InheritedModel<FavoriteModel> {}

Best practices in protractor for big pageObject files

In my previous protractor JS project (This new one I will do it with TS) I created one class for all my elements and another one for my functions, something like this:
specs
|_reportPage
|_lib
|_pageElements.js
|_pageFunctions.js
Then I was importing the files as necessary, in this way was easy to find the info since the element list was long.
So far all examples online for protractor TS projects are short pageObject files with a couple of elements and methods, but I would like to know how to correctly proceed when the page requires a lot of elements and functions/methods.
For example, lets say we have 5 specs under the same folder that test the same page and this page is full of fields and tables.
What would be the best practice here? create 1 pageobject for each spec, create one long class with all the elements and functions...?
Thanks for your time!
To Extend my answer you can add additional layer as a service which can execute several actions from the flow in different pages.
Code example:
export class E2EService {
mainPage: MainPage = new MainPage();
innerPage: InnerPage = new InnerPage();
doSomethingE2E() {
this.mainPage.headerPage.weDoSomething();
this.mainPage.contentPage.weDoSomething()
this.innerPage.somethingComplicated();
}
}
export class MainPage {
public readonly headerPage: HeaderPage;
public readonly contentPage: ContentPage;
}
export class InnerPage {
headerPage: InnerHeaderPage;
contentPage: InnerContentPage;
public somethingComplicated() {
this.headerPage.weDoSomething();
this.contentPage.weDoSomething();
}
}
export class ContentPage {
private readonly elements = {
// elements
};
public weDoSomething() {
// code
}
public getElements() {
return this.elements;
}
}
export class HeaderPage {
private readonly elements = {
btn1: element(by.id('')),
div: element(by.id('')),
h2: element(by.id(''))
};
public weDoSomething() {
// code
}
public getElements() {
return this.elements;
}
}
Based on Infern0's answer, I did dependency injection to the classes:
class HeaderElements {
foo = element(by.id("foo"));
//List goes on...
}
class HomePageElements {
foo = element(by.id("foo"));
//List goes on...
}
export class MainCommonElementsPage {
headerElements: HeaderElements;
homePageElements: HomePageElements;
constructor() {
this.headerElements = new HeaderElements();
this.homePageElements = new HomePageElements();
}
}
Best practices, even for large Page Objects is this:
Each page should only have 1 page object class. All of the tools needed to access that page should be located here. Think of your page object as an API.
Don't break the PO into different parts, especially for large pages. You'll eventually need to modify the PO to adjust for content changes. Would you rather change 1 file or 12? This also ensures that each of your e2e tests will remain functional after you update the PO.
I have one PO that handles a page with a lengthy form. The form has 12 controls and three buttons (cancel, reset, and submit). I have about 30 functions that deal with the form. I don't like having more than 1-2 methods in my test, so if it gets more complicated, I add to the PO.

Organizing extensions in Kotlin

In Swift we usually use extensions as a way to organize methods in separate blocks and even files. This makes code much cleaner but it also allows us to do some tricks such as:
class API {}
extension API {
class Lists{}
}
extension Lists {
class Posts {
func latest() -> [Post] {
// get latest posts from a REST api
}
}
}
We can put any of the extension blocks in a separate file and it works perfectly in Swift.
Now one do the following to get the latest posts from the API in a clean way
let posts = API.Lists.Posts.latest()
Trying to convert that code into Kotlin I used SwiftKotlin converter tool that I thought that might work but it doesn't compile as It seems to be invalid:
class API {}
class API.Lists {}
class Lists.Posts {
companion object {
fun latest() {
// get posts
}
}
}
So I came up with the following that works fine and also compiles but it's not suitable for my case as methods can be quite long and I can't afford to have them all in one class in one file and I don't know how I can split them in multiple files.
class API {
class Lists {
class Posts {
companion object {
fun latest() {
}
}
}
}
}
Any suggestion is appreciated.
To put an extension on a companion object, you can write
fun API.Lists.Posts.Companion.latest() ...
You still need
class API {
class Lists {
class Posts {
companion object {
}
}
}
}
in a single file, but extensions can be defined elsewhere.
If you just want to mimic usage of these calls, you can use objects, like this for example:
object ApiPosts {
fun latest() {}
}
object ApiLists {
val Posts = ApiPosts
}
object API {
val Lists = ApiLists
}
API.Lists.Posts.latest()
But this is really not a Kotlin way, and in common case it's a bad practice to write in a language the way it's not supposed to.
One possible solution is to just extend the inner classes with normal functions not static ones (companion):
class ParentClass {
class InnerClass {
}
}
And in any other file you could do:
fun ParentClass.InnerClass.instanceMember() {
}
And for usage:
ParentClass.InnerClass().instanceMember()
Of course this isn't exactly like the Swift version but it's close enough.

TypeScript: Access global type hidden by local class definition?

Lets assume i have a class which has the same name as an previously defined type which is defined inside lib.d.ts. How would i make use of that type within this class.
For example, i have the class Event, which has to deal with the browsers Event object, which is defined as an interface in lib.d.ts.
export class Event { // own definition of Event which hides original Event
public dealWithBrowserEvent(event: Event): void { // Event object defined by lib.d.ts
// deal with it
}
}
How would i tell Typescript that this are two different types. Of course i could simply rename my class, but i don't want to do that, because the name is perfect for my use case.
You can archive this by doing so:
E.ts:
class CustomEvent
{
public dealWithBrowserEvent(event: Event): void
{
}
}
export default CustomEvent;
A.ts:
import Event from './E'
export class SomeClass
{
//Parameter e here is instance of your CustomEvent class
public someMethod(e: Event): void
{
let be: any;
//get browser event here
e.dealWithBrowserEvent(be)
}
}
More on declaration merging, and what can be merged and what not: link
I strongly recommend you not doing so. This code will lead to a lot of confusion for your colleagues reading/modifying it later, let alone headache of not being able to use in the same file standard class for Event.
In the meantime i found a quite doable solution. I defined an additional module which exports renamed interfaces. If i import this module, i can use the renamed types as if they would be original types.
browser.ts
// Event will be the one from lib.d.ts, because the compiler does not know anything about
// the class Event inside this module/file.
// All defined properties will be inherited for code completion.
export interface BrowserEvent extends Event {
additionalProperty1: SomeType;
additionalProperty2: SomeType;
}
If you don't need additional properties you can just do type aliasing:
browser.ts
// Alias for Event
export type BrowserEvent = Event;
event.ts
import {BrowserEvent} from './browser.ts';
export class Event { // Definition of Event hides original Event, but not BrowserEvent
public dealWithBrowserEvent(event: BrowserEvent): void {
// deal with it
}
}
I'm quite happy with this solution, but maybe there is a even better solution.

Actionscript in a single class or in multiple scenes?

I am completely new to Actionscript and Adobe Flash CS6 and for a little bit of fun I have decided to try and make a little game. I had a few newbie (or noob-y) questions to ask about a general implementation approach.
The documentation I've been reading so far suggests creating a new flash project, and then create a document class so:
package {
import flash.display.MovieClip;
public class MyMainClass extends MovieClip {
public function MyMainClass() {
}
}
}
and I am wondering if I use this MainClass to code the whole game or include actionscript within a scene and have multiple scenes, or some combination of both.
Lets say I had a wanted 5 Levels in my game, would I do something like:
package {
import flash.display.MovieClip;
public class MyMainClass extends MovieClip {
public function MyMainClass() {
StartLevel1();
StartLevel2();
StartLevel3();
StartLevel4();
StartLevel5();
}
public function StartLevel1() {
// Do something
}
public function StartLevel2() {
// Do something
}
public function StartLevel3() {
// Do something
}
public function StartLevel4() {
// Do something
}
public function StartLevel5() {
// Do something
}
}
}
or create 5 scenes with actionscript in each scene?
Can anyone provide me with a bit of a starting point?
Thanks
I don't know of anyone who has anything good to say about scenes.
However, as you intuit, the timeline itself is a wonderful tool for managing the state of your Flash assets over time. If you use it, you also get the hidden advantage that you don't have to download 100% of your file to be able to use it (so you can reduce or even eliminate the need for a preloader by unchecking "Export in frame N" on your library symbols.
Lars has quite rightly pointed out that there are very few developers who understand this technique, and I know of exactly one who can and will help people who are interested in exploring this technique. That person is helping you right now. So if you choose to go that way, keep in mind you are mostly on your own except if I happen to notice your post and respond to it.
I am not in favor of timeline scripts, with a very few exceptions. What I suggest is a "both and" approach, where you use a Document Class to control timeline instances.
Your document Class might look something like this:
public class Game extends MovieClip {
protected var _level:ILevel;//Interface your Level MovieClips will implement
protected var levelController:LevelController = new LevelControler();
protected var currentLevel:int;
protected var maxLevels:int = 5;
public function Game() {
levelController.addEventListener(LevelEventKind.LEVEL_COMPLETE, nextLevel);
levelController.addEventListener(LevelEventKind.LEVEL_FAILED, gameOver);
startLevel(currentLevel);
}
public function startLevel(levelNumber:int):void {
goToLabel('Level' + String(levelNumber));
}
public function get level():ILevel {
return _level;
}
public function set level(value:ILevel):void {
_level = value;
//internally, this should release all listeners to the last
//level object (if any) so you don't get a memory leak
levelController.level = _level;
}
protected function nextLevel(e:Event):void {
if (currentLevel < maxLevels) {
startLevel(++currentLevel);
} else {
//do you won logic here
}
}
protected function gameOver(e:Event):void {
//do bombed out logic here
}
protected function goToLabel(label:String):void {
for each (var frameLabel:FrameLabel in currentLabels) {
if (frameLabel.name==label) {
//if your swf is media-heavy, may want to check that frame
//is loaded if you chose to reduce/eliminate preloader
goToAndStop(label);
return;
}
}
trace('no such label as', label);
}
}
What this gets you is a game where you can change how the different levels look without changing a single line of ActionScript, and you can change how they work by assigning different Base Classes that implement ILevel slightly differently. You can also change your functionality by swapping out different flavors of LevelController, but your Main Document Class (Game in this instance) would be aware of this change (wheras the other changes could be made without altering Game at all).