Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MV* in Polymer, models and services as polymer-elements?

Say I want two views (polymer-elements) to share a model for example.

In Angular the model would live in a singleton service that gets injected into the views, both views read from the same source.

I tried emulating this approach with Polymer so I can do something like:

<polymer-element name="view1">
  <template>
    <my-model></my-model>
    ...
  </template>
  ...
</polymer-element>

<polymer-element name="view2">
  <template>
    <my-model></my-model>
    ...
  </template>
  ...
</polymer-element>

I like this approach because it's a declarative way of defining dependencies, and it basically works the same as <core-ajax> and other "out of the box" Polymer elements.

With this way I need to wait for the domReady lifecycle callback before I can interface with any element declared in the template, so this is where I'm holding my initialisation logic at the minute. The problem is that this callback gets called once for each <my-model> element declared (so <my-model> would be initialised twice in this example because it's present both in <view1> and <view2>). To make sure that my model follows the singleton pattern I have to move state outside of the element instance, something like this:

 <polymer-element name="my-model">
   <script>
    (function(){
      // private shared state
      var instances = [], registered; // pattern variables
      var foo; // state, model, whatever

      // element init logic
      Polymer('my-model', {
        // Polymer callbacks
        domReady: function(){
          if (registered === (registered=true)) return;
          // singleton init logic
          foo = 'something';
          // event handlers
          this.addEventListener('foo', function(){ foo += 'baz'; });
        },
        attached: function() { instances.push(this); },
        detached: function(){
          instances = instances.filter(function(instance){
            return instance !== this;
          }.bind(this));
        },
        // element API
        update: doSomething,
        get state() { return foo; }
      });
      // private functions
      function doSomething(){ foo += 'bar' }
    })();
  </script>
</polymer-element>

So it works but it looks wrong to me. Is using <polymer-element> generally incompatible with the singleton pattern? Should I move away from Polymer for models and services? How do Polymer core-elements get away with it?

[EDIT] I added some event listeners to the initialising code above. They're only registered in one instance to avoid the listeners triggering multiple times across multiple instances. What would happen if the instance where the event handlers are declared gets removed? Will that not break the asynchronous logic?

like image 630
Renaud Avatar asked Oct 14 '14 14:10

Renaud


1 Answers

I'd go like this:
Define your model on the main page and call it from your views.

if it gets removed you could:
1 - listen for the "detached" lifecycle callback and inside it register it imperatively or
2 - store stuff on a prototype build in a higher level object and access it the way you fancy the most.
3 - if all fails, (i'm not sure it will but i guess so as i've yet to use this kind of implementation, as of now i talk to php and pass around objects i need persistent) you could use a "prepareForRemoval" knowing you will leave the instance, local storage your stuff and do number 1 then "recoverFromRemoval" if you know what i mean by camel casing prototype suggestions.

Anyways i'm not very fond of singletons. Polymer is powerful front-end stuff but i'm not sure it's the best way to go about it.

in the API docs they do not mention the possibility of getting it cut off (as you can see) but i honestly think you're right and you would lose your stuff.
That's just my 2 cents actually just a inellegant sollution i came up for at this very moment, maybe @ebidel, @DocDude or @dodson can help us in that matter but you can't really tag em here on SO i'll tag em on G+ for us, you sir got me intrigued.
BTW why would you move away from your main page? there's no point for it in polymer you should change the content dynamically not get away from it. what would be the usage scenario?


ps.: sorry, i hate capitalizing proper nouns.Get over it

EDIT (wouldn't fit on the comments):

I expressed myself wrong. Anyways i strongly think i wasn't understanding what you wanted.
Well, if i got it right this time yes it will fire multiple times (they are supposed to), but it shouldn't cut others out once a particular view gets removed.

As for your initialisation logic i would go about adding a listener to the window or document (i think window is more advisable) itself waiting for the 'polymer-ready' event.

"To make sure that my model follows the singleton pattern I have to move state outside of the element instance"

Yes thats right. but don't wait for the domready in it's prototype, instead use a construct or contruct-like and call it it as the callback of the aforementioned event listener. i'll edit my answer to make it clearer (if it's not, let me know) when i get back home.
i hope you got i meant.

if you don't i'll be back soon.

like image 69
Caio Wilson Avatar answered Sep 27 '22 18:09

Caio Wilson