How to do true MVVC in Typescript {N} app


#1

I am struggling with how to properly architect an application using Typescript and NOT angular. So a page’s hierarchy should look like this:

/home
- home.xml
- home.css
- home.ts
- home-model.ts

home-model.ts contains a class that extends observable like this:

export class HomeModel extends Observable {
    constructor() {
        super();
    }

    public header_text: string = 'This Week';
}

In that class, I do not have access to the Page, therefore dont have access to any views within it to, for example, animate them. I think if I am following mvvc correctly though, all view manipulation should be done in home.ts. But here is where I am struggling:

Say I want to animate a view to pop up over my main view based on a tap, and operations that happen in that second overlay view will affect some observable properties. So say I wanted to change header_text. Here’s how I am doing it now, although it feels very wrong, and there are cases where my UI isnt noticing the changes to my observable class properties:

in home.ts:

export function loaded(args: EventData) {
    page = <Page>args.object;
    page.bindingContext = new HomeModel();
    page.bindingContext.set('editHeader', function() {
        page.bindingContext.set('header_text', 'Next Week');
        page.getViewById('header_text_view').animate({
            opacity: 1,
            duration: 1000
        })
    })
}

// then in my xml

<Button tap="{{editHeader}}" text="Change to Next Week" />

Thats not a real function in my app, but it illustrates my problem. I am doing some more complicated things like this:

export function loaded(args: EventData) {

    ...
   
    page.bindingContext.set('editFamily', function(args) {
        let families = page.bindingContext.get('families');
        let family = families.filter(item => item.id === args.object.id)[0];
        page.bindingContext.set('editingFamily', family);
        showSettings('/views/components/editfamily/editfamily.xml');
        page.bindingContext.set('settingsTitle', 'Edit Family');
        page.getViewById('family_name').text = family.get('name');
        page.getViewById('family_email').text = family.get('email');
    })
}

function showSettings(viewPath) {
    console.log(viewPath);
    page.bindingContext.set('settingsShown', true);
    let deviceHeight = screen.mainScreen.heightDIPs;
    settingsContainer.translateY = deviceHeight + 30;
    settingsContainer.animate(<AnimationDefinition>{
        translate: {x: 0, y: 0},
        duration: 300,
        curve: AnimationCurve.cubicBezier(0.1, 0.1, 0.1, 1)
    })
    settingsOverlayContainer.opacity = 0;
    settingsOverlayContainer.animate({
        opacity: 1,
        duration: 100
    })
    var container: StackLayout = page.getViewById('settings_view');
    container.removeChildren();
    let path = fs.knownFolders.currentApp().path;
    let component = builder.load(path + viewPath);
    container.addChild(component);

    let containerBounds = settingsContainer.ios.bounds;
    if (!blurView) {
        blurView = UIVisualEffectView.alloc().initWithEffect(UIBlurEffect.effectWithStyle(UIBlurEffectStyleLight));

        blurView.frame = {
            origin: { x: containerBounds.origin.x, y: containerBounds.origin.y - 20 },
            size: { width: containerBounds.size.width, height: containerBounds.size.height + 20 }
        };
        blurView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        settingsContainer.ios.addSubview(blurView);
        settingsContainer.ios.sendSubviewToBack(blurView);
    }
}

I could use some pointers on best practices for this sort thing. I am also calling services from a shared class that saves info to firebase.

This is my whole repo if you really want to dig in and give me some pointers: https://github.com/davecoffin/nannyshifts


#2

@jen.looper any love?