Let Me Tink About It
Let Me Tink About It

Reputation: 16102

Polymer 1.x + Firebase 2.x: Firebase data does not load on first render after login

On the first load of the page after a user login event, I want to populate the items property with a set of objects stored in my Firebase.

A achieves my desired behavior.

A
<firebase-query
    id="query"
    ...
    path="users/[[user.uid]]/widgets"
    data="{{items}}">
</firebase-query>

B does not.

B
<firebase-query
    id="query"
    ...
    path="widgets"
    data="{{items}}">
</firebase-query>

When using B, I expect to see the items object populate, but instead the items object is null. However, if I refresh the browser manually (without logging out) the element behaves as expected. However, if I log out (then refresh while logged out), the problem reappears until I reload again. If I only log out then log back in the problem does not reappear due, I think, in part to the fact the app does not reset as described here.

Why does A work? But not B? And what modifications must I make to B to get it to work? (Because I want to store the widgets from the root/widgets/ path and not have to store that detail under the users/... path.

Previous Unsuccessful Attempts

My current (unproven) theory is that the in the case of B (when the URL is constant/static, i.e., widgets/) firebase-query gets involved in some sort of race condition; and only fetches the data after some lifecycle event and doesn't attempt to re-fetch the data. On the other hand, the firebase-query does attempt to re-fetch when the path is dynamically updated based on the databinding in the path attribute (i.e., path="users/[[user.uid]]/widgets"). Is this theory correct? Or is there some other cause? Do I need to imperatively fetch the data after some event? If so, how can I accomplish all this?

I have tried the following ideas without success.

C
user: {
  type: Object,
  notify: true,
  observer: '_userChanged',
},

_userChanged: function() {
  this.$.query.path = 'widgets';
  var items = this.$.query.ref.child('widgets');
  this.set('items', items);
},
D
<firebase-query
    id="query"
    ...
    path="[[path]]"
    data="{{items}}">
</firebase-query>

<script>
...
  properties: {
    path: {
      type: String,
      value: function() {
        return 'widgets';
      },
    }
  },
...
</script>

Also, on the Polymer Slack Site, @will-in-china says:

I have had problems with the data loading the first time, I found that if i don't have more than one reference to the same path, i dont get this issue.

I'm not sure what that means in this context as I only have one reference in my element (and app) to the path path="widgets" inside a firebase-query element.

Upvotes: 0

Views: 223

Answers (3)

Neiro
Neiro

Reputation: 66

I'm coming late but I resolve this using dom-if condition if user this prevent make a request if no are an user authenticate

Upvotes: -1

Suprada
Suprada

Reputation: 1

"When using A, I expect to see the items object populate, but instead the items object is null. However, if I refresh the browser manually (without logging out) the element behaves as expected. However, if I log out (then refresh while logged out), the problem reappears until I reload again."

I'm seeing similar behavior in my app. In my case, it is related to firebase-auth and firebase-query race conditions. In my case,

  1. When I login, the firebase-auth is firing at the same time/after firebase-query. In this case, my query is rejected because of invalid permission - I am querying before being authenticated. Error log excerpt:

    "detail: Error: permission_denied at /parents: Client doesn't have permission to access the desired data. …, type: "error", target: firebase-query .... firebase-query does not retry after authentication is complete. I don't know if this is a bug.

  2. When I refresh after logging in, since I am already authenticated, the query is successful.

To debug this issue, I added a on-error handler to print out the permissions. To get around this issue, I am using the disabled property. When the page is first loaded, all queries are disabled. Only when authentication is successful, I toggle "disabled" at which point queries fire successfully.

signIn: function(){
  var email = this.user.email;
  var password = this.user.password;
  this.$.auth.signInWithEmailAndPassword(email, password)
     .then(function(response){
		self.disabled = false;
		// console.log('signin', response);
	 })
	.catch(function(error){
		console.log('auth-element:signIn error is', error.detail);
	 })
	.then(function(){
	   // call other functions
	});
 },
handleError: function(error){
  console.log('error message', error.detail.message);
},
<firebase-query
   id = "query"
   app-name="my-app"
   path = "/shoeboxes"
   data = "{{datauid}}"
   on-error="handleError"
   disabled="{{disabled}}">
</firebase-query>

Hope this helps. Basically, I'm finding that with polymer and firebase, promises are better than automagical bindings...

Upvotes: 0

Robert Rowntree
Robert Rowntree

Reputation: 6289

i dont think this is your specific issue but it may be similar in that after a login -> setNewRoute(nextPage) i did not get a render and i changed the subsequent template ( Iron-Ajax ) to fire manually rather than via the observer.

  loggon: function parseLogin(user, password) {
...

     Parse.User.logIn(_user, _pass).then(function() {
      page('/channels');

---
channels.render ...

      _render: function() {
        console.log('_render');
        this.$.get_channlinq.headers = hdr;
        //xhr params
        var body = this._setQry(this.params.channelId);
        this.$.get_channlinq.body = JSON.stringify(body);
        //fetch , load , template will render
        this.$.get_channlinq.generateRequest(); 

Upvotes: 0

Related Questions