If there is a list which should be rendered from an array, and the array will be passed from the grand-grand-grand-grand-grand-parent custom element. That will be super annoying.
Is there a global state management solution for lit-element, just like redux?
Yes, check out LitState (npm package name lit-element-state).
I created this specially for LitElement. It has the same mindset: simple, small and powerful.
Because it is created specially for LitElement, it integrates very well and therefore the usage is very simple. You make a state object like this:
import { LitState, stateVar } from 'lit-element-state';
class MyState extends LitState {
#stateVar() myCounter = 0;
}
export const myState = new MyState();
Usage without #decorators, look here.
Then you can use the state in your components like this:
import { LitElement, html } from 'lit-element';
import { observeState } from 'lit-element-state';
import { myState } from './my-state.js';
class MyComponent extends observeState(LitElement) {
render() {
return html`
<h1>Counter: ${myState.counter}</h1>
<button #click=${() => myState.counter++}></button>
`;
}
}
When you add the observeState() mixin to your component, the component will automatically re-render when any stateVar they use changes. You can do this with any amount of component and states and it will all automatically stay synchronized thanks to the observeState() mixin.
LitElement is a library and you can use any library for state management that you want. Just subscribe to the store in the constructor or connectedCallback (unsubscribe in disconnectedCallback) and change the components' properties when the store notifies you of a change.
Here you have some PWA helpers that works with litElement and you have one for Redux.
https://github.com/Polymer/pwa-helpers#connect-mixinjs
I am late in the game, but this can be quite usefull:
https://www.npmjs.com/package/#lit-app/state
#lit-app/state is a global state management, integrating with lit web-components.
Why a new state-management tool ?
There are plenty options available for state management, so why yet another one?
Some existing options are too heavy. In my opinion, managing state should be lean and simple. Redux, for instance falls into this category.
Some solutions designed for lit (for instance lit-state) do not support Typescript and do not take advantage of lit#2 Reactive Controlers, very well suited for hooking external features into templating lifecyce.
Some elegant ideas were worth pursuing (for instance this tweet, or this post.
How to use it?
import { State, StateController, property } from "#lit-app/state";
import { LitElement } from "lit";
// declare some state
class MyState extends State {
#property({value: 'Bob'}) name
}
const myState = new MyState()
// declare a component
class StateEl extends LitElement {
// StateController is a Reactive Controller binding myState with the element
state = new StateController(this, myState)
override render() {
return html`
<div>This will be updated when the state changes: ${myState.name}</div>
`;
}
}
// changing the state will reflect in the template
myState.name = 'Alice'
I'd look into MobX which is an extremely popular framework independent state management library
"MobX is unopinionated and allows you to manage your application state outside of any UI framework. This makes your code decoupled, portable, and above all, easily testable." - (Github)
Related
I am working in actionscript3, and since I'm self-taught, I think I've developed some bad habits, including coding on the timeline and using multiple scenes.
I am hoping to rectify this now that I'm working on a larger project.
Based on what I've read, linking multiple .fla files together is a better practice, each with their own document class. Is that correct?
If so, how do I load one .fla with its document class and then link that into the subsequent .fla file (instead of using scenes)? Or am I misinterpreting what was recommended?
Thanks!
There's no point to split your application in several loadable modules unless you have any of the following preconditions:
you have smart resource management to load and unload content
if you put everything into one file it gets just too big and hard to work with in design time or it takes far too long to compile
Regular AS3 alternative to working with scenes is creating/destroying content instances and using the main document class as their manager. You design content in the library and create behavior AS3 classes for them. Lets say, you have two content classes A and B. At the start the manager should show one of them and wait for the signal to show next one:
private var APage:A;
private var BPage:B;
gotoA();
function gotoA():void
{
if (BPage)
{
BPage.destroy();
removeChild(BPage);
BPage.removeEventListener(Event.CLOSE, gotoA);
}
APage = new A;
APage.addEventListener(Event.CLOSE, gotoB);
addChild(APage);
}
function gotoB():void
{
if (APage)
{
APage.destroy();
removeChild(APage);
APage.removeEventListener(Event.CLOSE, gotoB);
}
BPage = new B;
BPage.addEventListener(Event.CLOSE, gotoA);
addChild(BPage);
}
So, both A and B should have respective methods .destroy() that release used resources, unsubscribes methods from events, remove display objects, and so on, and they both should fire Event.CLOSE when they're done.
If you have many pages like that, you need to go for more algorithmic approach. For example, to create class BasicPage which will interact with manager and have the methods needed in all pages already declared:
package
{
import flash.display.Sprite;
class BasicPage extends Sprite
{
// A reference to the page manager instance.
public var Manager:PageManager;
public function destroy():void
{
while (numChildren > 0) removeChildAt(0);
Manager = null;
}
// Subclasses will have an access to this method to tell manager to show another page.
protected function showOtherPage(pageClass:Class):void
{
Manager.showPage(pageClass);
}
// A method that is called by manager when everything is ready.
// If page should take any actions on start it is a good idea to override this method.
public function startEngine():void
{
}
}
}
Then, example page A:
package
{
import flash.events.MouseEvent;
public class A extends BasicPage
{
// Lets say, class A in library have a designed button named Click.
public var Click:SimpleButton;
// We have things to undo here.
override public function destroy():void
{
Click.removeEventListener(MouseEvent.CLICK, onClick);
Click = null;
// Pass the destruction to superclass so it wraps its existence either.
super.destroy();
}
override public function startEngine():void
{
Click.addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void
{
// Lets use inherited method to show other page.
showOtherPage(B);
}
}
}
So, PageManager will be like:
package
{
public class PageManager extends Sprite
{
private var Page:BasicPage;
// constructor
function PageManager()
{
super();
showPage(A);
}
function showPage(pageClass:Class):void
{
if (Page)
{
Page.destroy();
removeChild(Page);
Page = null;
}
Page = new pageClass;
Page.Manager = this;
addChild(Page);
Page.startEngine();
}
}
}
This all could look scary at first, but it really isn't. PageManager will always have a current page, once there's a need to show another page, the current will be destroyed on a regular basis. Each page class will tend to its own content, which makes coding simpler, for you don't need to see the whole picture. If you need any persistent data, keep it in the PageManager so each page will have access to the data with no need for the pages to communicate with each other.
just thought I would share something I have found to help delivering data across an application I am wondering what others think about this I wanted to have a way to capture event bubbling up back down to other components but in a way that it would make it easy to use anywhere in may app so this is what i came up with.
I Extend the Application class and wrap in an abstract function registering a function of any component anywhere and capture it at the top most level and pass to where ever i chose to.
public class AxApplication extends Application
{
public var ___registeredEvents:Array = new Array();
public var ___registeredFunctions:Array = new Array();
function AxApplication()
{
super();
}
public function localRegisterForEvent(e:Event,func:*,caller:*):void
{
caller.addEventListener(e.type,localCallerEventHandler,true,3);
caller.addEventListener(e.type,localCallerEventHandler,false,3);
___registeredEvents.push(e);
___registeredFunctions.push(func);
}
public function localCallerEventHandler(e:*):void
{
if(e!=null)
{
for(var i:int = 0 ; i< ___registeredEvents.length; i++)
{
if(e.type == ___registeredEvents[i].type)
{
___registeredFunctions[i](e);
//the registered function gets called
//there no garbage collection implemented!
}
}
}
}
}
I think that is not a very useful solution. Why? Because you scatter AxApplication references around the application. Views and Model instance don't need any references to the application at all. It would be better to to implement a controller layer which uses a simple eventBus property, which could look like:
private static const _EVENT_BUS:IEventDispatcher = FlexGlobals.topLevelApplication;
protected final function eventBus():IEventDispatcher {
return _EVENT_BUS;
}
If you implement a base view controller/mediator (depending from which framework you're coming), you don't have any reference to non-framework classes at all, which makes it highly reusable. It is just a simple reuse of the Application singleton which you use to dispatch system wide events. You register listeners in the view controller/mediator and update the views or models accordingly. RobotLegs for example uses a system wide event dispatcher as well.
Why not just using the parentApplication approach? Because you can't implement tests (the generated test-runner of IDEs won't extend your AxApplication) or just yank the components/models in a different application - that is basically not possible.
I have a custom Flex Toggleswitch component that changes the text values of the switch.
package skins
{
import spark.skins.mobile.ToggleSwitchSkin;
public class MyToggleSwitchSkin extends ToggleSwitchSkin
{
public function MyToggleSwitchSkin()
{
super();
selectedLabel="Serviceable";
unselectedLabel="Fault";
}
}
}
If I add the control using the MXML tag, it works fine. However, when I add the component using action script, it does not.
import skins.MyToggleSwitchSkin;
public function addToggle():void {
var myCustomToggle:MyToggleSwitchSkin = new MyToggleSwitchSkin();
hgroup.addElement(myCustomToggle);
}
The control dsiplays but will not activate.
Any ideas what I have missed?
Without seeing your MXML Code, it's tough to compare your two approaches, but I believe #al_Birdy addressed the problem. You've created a custom ToggleSwitchSkin; not a custom ToggleSwitch.
Modify your addToggle() method like this:
public function addToggle():void {
var myCustomToggle:MyToggleSwitch = new MyToggleSwitch();
myCustomToggle.setStyle('skinClass',skins.MyToggleSwitchSkin);
hgroup.addElement(myCustomToggle);
}
I suspect you'll have better luck.
The ScalaDoc for the applet class is pretty thin on details on how you actually override the ui piece and add components. It says "Clients should implement the ui field. See the SimpleApplet demo for an example."
Where is this SimpleApplet demo?
Barring that, does anyone have some simple source code of using the Scala Applet class, rather than the JApplet class directly?
Thanks
The more recent ScalaDoc may be slightly more helpful (in particular, the new version of ScalaDoc allows you to show/hide concrete members so you can focus on what you must implement).
It should be noted that you don't have to define an object named ui that extends UI. What the ScalaDoc says is both more accurate and more flexible -- "implement the ui field". Because of the Uniform Access Principle, you're free to implement the ui field as a val or an object (similarly, you can use a val or var to implement a def). The only constraints (as reflected in the ScalaDoc as val ui : UI) are that
the ui has to be a UI, and
the reference to the ui has to be immutable
For example:
class MainApplet extends Applet {
val ui = new MainUI(Color.WHITE)
class MainUI(backgroundColor: Color) extends UI {
val mainPanel = new BoxPanel(Orientation.Vertical) {
// different sort of swing components
contents.append(new Button("HI"))
}
mainPanel.background = backgroundColor // no need for ugly _=
contents = mainPanel
def init(): Unit = {}
}
}
Finally found some source that shows what you need to do:
http://scala-forum.org/read.php?4,701,701
import swing._
import java.awt.Color
class MainApplet extends Applet {
object ui extends UI {
val mainPanel = new BoxPanel(Orientation.Vertical) {
// different sort of swing components
contents.append(new Button("HI"))
}
mainPanel.background = Color.WHITE
contents = mainPanel
def init():Unit = {}
}
}
In other words you define an object named ui that extends UI. I never would have thought of that. That ScalaDoc needs some serious work.
I develop with FlashDevelop3 R2 and the Flex 3.3 SDK and there are many occasions where I must use the embed metadata tag as such:
[Embed(source="path/to/file")]
private var Asset:Class;
I understand the above all well and good, and I am thankful it exists because I do not like to open the flash IDE too often.
When I am going through other authors classes lately, I have found an interesting metadata tag that I do not understand:
[Event(name="", type="")]
I have yet to see a situation where I require this, and furthermore I really just do not understand what it is for.
Thank in advance for your help.
Brian Hodgeblog.hodgedev.com hodgedev.com
These [Event(name, type)] declarations describe which events a class instance is likely to dispatch.
They are actually useful for code completion - for instance when you type: mySprite.addEventListener(, your code editor (Flex Builder or FlashDevelop) will display a meaningful list of events that this object can dispatch.
So you can add these declarations in your code and benefit from a richer code completion.
Also note that this works with custom Event classes (see FlashDevelop's new Event class template).
package mycomp {
import flash.events.Event;
public class MyEvent extends Event {
public const SOME_EVENT:String = "someEvent";
// required Event type declarations
}
}
package mycomp {
[Event(name="someEvent", type="mycomp.MyEvent")]
public class MyComp extends Sprite {
}
}
package myproject {
import mycomp.MyComp;
public class MyProject {
function MyProject() {
var mc:MyComp = new MyComp();
mc.addEventLister( //completes: SOME_EVENT + Sprite events
}
}
}
We use it for binding custom events to our custom MXML components. This tag allows you to reference it from MXML. See documentation:
[Event(name="enableChanged", type="flash.events.Event")]
class ModalText extends TextArea {
...
}
<MyComp:ModalText enableChanged="handleEnableChangeEvent(event);"/>
The compiler will complain, however, if you try to refer to an event on an mxml tag that was not declared with an event metatag.