Search code examples
dartpolymerdart-polymer

Where is it best to handle the business logic in my Polymer app?


So I've got a pure Polymer app. Currently, in some elements I have methods that call to my Firebase database, and handle related processing and whatnot, which I then <template repeat=...> into my element. This doesn't seem right, as it's encouraged that Polymer elements are reusable. I also do things like dependency injection e.g. <my-element app="{{app}}"> so I have access to global settings and such.

What I end up with is a structure like:

index.dart -> <my-app-as-an-element app=... -> <child-elements app=...

Is there a better way to architect things? Like, should the business logic happen in lib/src/some_controller.dart which is imported into index.dart and has the business logic methods? How would I pass that through to the child elements that need access to those methods? Basically, some best practices and approaches would be helpful.

Code: http://github.com/davenotik/dart-stack/tree/dev


Solution

  • I use Model classes which are structured in a way that reflects the GUI structure and I bind them to the Polymer elements like shown below. Similar with the controllers but this would get out of proportion for an SO answer.

    I didn't test this code - this is just to demonstrate the idea.

    import 'package:polymer/polymer.dart';
    
    class AppModel {
      var loginModel = new LoginModel();
      var moviesModel = new MoviesModel();
      var actorsModel = new ActorsModel();
    }
    
    class LoginModel extends Observable {
      @observable bool isAuthenticated;
      @observable String userName;
      @observable String email;
    }
    
    class MoviesModel {
      final List<MovieModel> movies = toObservable(<MovieModel>[]);
    }
    
    class MovieModel extends Observable {
      @observable String id;
      @observable String name;
      @observable int rating;
      final List<ActorModel> actors = toObservable(<ActorModel>[]);
    }
    
    class ActorsModel {
      final List<ActorModel> actors = toObservable(<ActorModel>[]);
    }
    
    class ActorModel extends Observable {
      @observable String id;
      @observable String firstName;
      @observable String middleName;
      @observable String lastName;
      @observable DateTime birthDate;
      final List<MovieModel> movies = toObservable(<MovieModel>[]);
    }
    

    .

    <polymer-element name="login-dropdown">
      <template>
        <template if="model.isAuthenticated">
          <label for="userName"><input id="userName" value="{{model.userName}}" disabled></label>
          <label for="email"><input id="email" value="{{model.email}}" disabled></label>
          <button on-click="{{handleSignOut}}">Sign out</button>
        </template>
        <template if="!model.isAuthenticated">
          <label for="userName"><input id="userName" value="{{model.userName}}"></label>
          <button on-click="{{handleSignIn}}">Sign out</button>
        </template>
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
        @CustomTag('login-dropdown')
        class LoginDropdown extends PolymerElement {
          LoginDropdown.created() : super.created();
    
          @PublishedProperty(reflect: true) MoviesModel model;
        }
      </script>
    </polymer-element>
    
    <polymer-element name="app-element">
      <template>
        <header-toolbar>
          <login-dropdown-button>
            <login-dropdown model="{{model.loginModel}}"></login-dropdown>
          </login-dropdown-button>
        </header-toolbar>
        <tab-control>
    
          <tab-panel label="Movies">
            <movies-panel model="{{model.moviesModel}}"></movies-panel>
          </tab-panel>
    
          <tab-panel label="Actors">
            <actors-panel model="{{model.actorsModel}}"></actors-panel>
          </tab-panel>
    
        </tab-control>
    
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
    
        @CustomTag('app-element')
        class AppElement extends PolymerElement {
          AppElement.created() : super.created();
    
          AppModel model = new AppModel();
        }
      </script>
    </polymer-element>
    
    <polymer-element name="movies-panel">
      <template>
        <template repeat="{{movie in model.movies}}">
          <movie-panel model="{{movie}}"></movie-panel>
        </template>
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
    
        @CustomTag('movies-panel')
        class MoviesPanel extends PolymerElement {
          MoviesPanel.created() : super.created();
    
          @PublishedProperty(reflect: true) MoviesModel model;
        }
      </script>
    </polymer-element>
    
    <polymer-element name="movie-panel">
      <template>
        <div data-id="{{model.id}}">
          <div><span>Name:</span><span>{{model.name}}</span></div>
          <div><span>Rating:</span><span>{{model.rating}}</span></div>
        </div>
    
        <template repeat="{{actor in model.actors}}">
          <actor-panel model="{{actor}}"></actor-panel>
        </template>
    
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
    
        @CustomTag('movies-panel')
        class MoviesPanel extends PolymerElement {
          MoviesPanel.created() : super.created();
    
          @PublishedProperty(reflect: true) MoviesModel model;
        }
      </script>
    </polymer-element>
    
    <polymer-element name="actors-panel">
      <template>
        <template repeat="{{actor in model.actors}}">
          <actor-panel model="{{actor}}"></actor-panel>
        </template>
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
    
        @CustomTag('actors-panel')
        class ActorsPanel extends PolymerElement {
          ActorsPanel.created() : super.created();
    
          @PublishedProperty(reflect: true) ActorsModel model;
        }
      </script>
    </polymer-element>
    
    <polymer-element name="actor-panel">
      <template>
        <div data-id="{{model.id}}">
          <div><span>First name:</span><span>{{model.firstName}}</span></div>
          <div><span>Middle name:</span><span>{{model.middleName}}</span></div>
          <div><span>Last name:</span><span>{{model.lastName}}</span></div>
          <div><span>Date of birth:</span><span>{{model.birthDate}}</span></div>
        </div>
    
        <template repeat="{{movie in model.movies}}">
          <movie-panel model="{{movie}}"></movie-panel>
        </template>
    
      </template>
      <script type="application/dart">
        import 'package:polymer/polymer.dart';
        import 'model.dart';
    
        @CustomTag('actor-panel')
        class ActorPanel extends PolymerElement {
          ActorPanel.created() : super.created();
    
          @PublishedProperty(reflect: true) ActorModel model;
        }
      </script>
    </polymer-element>   
    

    See also Use a class as attribute for a dart polymer element for more interesting options.