Skip to content
This repository has been archived by the owner on Jan 26, 2021. It is now read-only.

Issue with Set Mutations #27

Closed
agnosticdev opened this issue Apr 27, 2015 · 18 comments
Closed

Issue with Set Mutations #27

agnosticdev opened this issue Apr 27, 2015 · 18 comments

Comments

@agnosticdev
Copy link

I have been experiencing issues with Set Mutations. Every time I try and create a very basic Set Mutation, like so:

var dispatch_activity = ParseReact.Mutation.Set(parseObj.id, { update_field: String(c) } );

///
dispatch_activity.dispatch();

I would get the following error:

Uncaught TypeError: Cannot read property 'className' of undefined   parse-react.js:2497

Based upon the documentation and the todo Demo it looked like my code was correct, so I thought I would take a look at the code in parse-react.js at 2497.

On the code in parse-react.js it looks like the changes object is referencing id.className from the latest object, which I found not to hold that data. Here is the snippet I am referring to:

var potentials = SubscriptionManager.queriesForFields(changes.latest.id.className, changes.fields);
  for (i = 0; i < potentials.length; i++) {
    if (visited[potentials[i]]) {
      continue;
    }
    subscriber = SubscriptionManager.getSubscription(potentials[i]);
    if (QueryTools.matchesQuery(changes.latest, subscriber.originalQuery)) {
      subscriber.addResult(changes.latest);
      ObjectStore.addSubscriber(changes.latest.id, potentials[i]);
    }
  }
  if (changes.latest.id.className === '_User') {
    var currentUser = Parse.User.current();
    if (currentUser && changes.latest.id.objectId === currentUser.id) {
      LocalSubscriptions.currentUser.update(changes.latest);
    }
  }

If I reworked this block of code for changes to reference id.className directly then everything worked perfectly in my Set Mutation. Like so:

  var potentials = SubscriptionManager.queriesForFields(changes.id.className, changes.fields);
  for (i = 0; i < potentials.length; i++) {
    if (visited[potentials[i]]) {
      continue;
    }
    subscriber = SubscriptionManager.getSubscription(potentials[i]);
    if (QueryTools.matchesQuery(changes.latest, subscriber.originalQuery)) {
      subscriber.addResult(changes.latest);
      ObjectStore.addSubscriber(changes.id, potentials[i]);
    }
  }
  if (changes.id.className === '_User') {
    var currentUser = Parse.User.current();
    if (currentUser && changes.id.objectId === currentUser.id) {
      LocalSubscriptions.currentUser.update(changes.latest);
    }
  }

Just wondering if anyone else has seen this issue or if it is something that I am possibly doing wrong.

@andrewimm
Copy link
Contributor

To help debug this, can you tell me what parseObj is? Is it the result from an observe subscription, or is it a Parse.Object?

@agnosticdev
Copy link
Author

The parseObj is part of an observe subscription that takes place in a parent component. Data is then passed down to a child component where I use it to create a Set Mutation. So the Set Mutation looks like this in the child component:

// I have validated that the correct data, className and objectId are in parseObj.id
var dispatch_activity = ParseReact.Mutation.Set(this.props.someParentObject.parseObj.id, { 
  update_field: String(c) 
} );
...
//parent component
dispatch_activity.dispatch();

Then I pass the dispatch_activity variable back to the parent and dispatch it there. The same issue arises if I dispatch in the child component also.

@agnosticdev
Copy link
Author

I put together a working example of the issue I described above.

var ParentNode = React.createClass({
  mixins: [ParseReact.Mixin], // Enable query subscriptions

  observe: function() {
    return {
      subscription_data: (new Parse.Query('ParentObject')).include('child')
    };
  },

  render: function(){
    var self = this;
    var parentComponent = this.data.subscription_data.map(function(object){
        return(
           <div className="row" key={object.id}>
               <h3>{object.parentTextData}</h3>
               <ChildNode key={object.child.id} childData={object.child} update={self._refresh} />
           </div>
        )
    });
    return (<div>{parentComponent}</div>);
  },

  _refresh: function(id, text){
    ParseReact.Mutation.Set(id, {
      childTextData: text
    }).dispatch();
     //Uncaught TypeError: Cannot read property 'className' of undefined  parse-react.js:2497
  }
});

var ChildNode = React.createClass({
  getInitialState: function() {
     return { textData: this.props.childData.childTextData};
  },
  render: function(){
     return (
        <div className="childNode">
           <div>{this.state.textData}</div>
           <button onClick={this._handleClick}>Update</button>
           <hr />
        </div>
     );
  },
  _handleClick: function(){
     var newText = 'Updated From Example!!!',
     self = this;

     this.setState({
        textData: newText,
     }, function(){
        self.props.update(this.props.childData.id, newText);
     });
  }
});

React.render(
  <ParentNode />, 
  document.getElementById('test')
);

I also put a live example from a test project I created here.

@andrewimm
Copy link
Contributor

Ah okay, that helped a lot. I've figured out the issue. Looks like the results of .include columns aren't being placed in the ObjectStore. I'll go fix that in storeQueryResults, and try to get a new release out in the next 24 hours.
I'm not sure if there's any simple workaround in the meantime. ObjectStore is intentionally hard to interact with from userspace

@agnosticdev
Copy link
Author

@andrewimm thank you very much, I appreciate it! There is the workaround that I described above:

  var potentials = SubscriptionManager.queriesForFields(changes.id.className, changes.fields);
  for (i = 0; i < potentials.length; i++) {
    if (visited[potentials[i]]) {
      continue;
    }
    subscriber = SubscriptionManager.getSubscription(potentials[i]);
    if (QueryTools.matchesQuery(changes.latest, subscriber.originalQuery)) {
      subscriber.addResult(changes.latest);
      ObjectStore.addSubscriber(changes.id, potentials[i]);
    }
  }
  if (changes.id.className === '_User') {
    var currentUser = Parse.User.current();
    if (currentUser && changes.id.objectId === currentUser.id) {
      LocalSubscriptions.currentUser.update(changes.latest);
    }
  }

I can just work locally with this temporary fix until the new release is out.
Again, thank you very much.

@andrewimm
Copy link
Contributor

Just released 0.2.1 on npm and to ParseCDN, which now places all nested query results in the ObjectStore. Running your example locally with the new version seems to work.
Let me know if you run into any trouble.

@agnosticdev
Copy link
Author

Thank you for this release. I just tested it my test project and all works well, so the set mutations seem to be working.

There seems to be another issue when you subscribe to a query that includes pointers to objects that are not set. For example an object may include pointers to one or both objects and when I query them it looks like this:

query.include("includeObjectOne");
query.include("includeObjectOne.childOne");
query.include("includeObjectOne.user_reference");
query.include("includeObjectTwo");
query.include("includeObjectTwo.childTwo");

When I try and subscribe to this query it throws these errors and warning:

Warning:  Attempted to flatten something that is not a Parse Object   parse-react.js: 2750
Error:  Uncaught TypeError: Cannot read property 'id' of undefined   parse-react.js: 1131

I have a feeling that the errors are due to my data set having pointer references to objects that are not set. I can put together a more thorough test tonight. How do you want me to handle this? Close this issue and open another one?

@naterubin
Copy link

I have run into the same issue where unset pointers produce a

cannot read property 'id' of undefined

error. Simply checking for the existence of cur before calling storeObject() on line 306 of ObjectStore.js fixed the problem for me.

@agnosticdev
Copy link
Author

@80vs90 thank you for sharing that workaround!

@andrewimm
Copy link
Contributor

Yep, when seeing a query like

query.include("includeObjectOne.childOne");

the code assumes the includeObjectOne column is filled. I patched this earlier today, but was hoping for another fix / feature release before bumping the version number again. I'll probably just go ahead and mark this as a 0.2.2 release.

@agnosticdev
Copy link
Author

Awesome, thank you @andrewimm

@andrewimm
Copy link
Contributor

Got a little over-eager on that release, missed an initial edge case. Grab 0.2.3 from npm, it should fix this issue.

@TimonSotiropoulos
Copy link

I had the same initial issue when trying to an Add Mutate function as in the first post. I upgraded to 0.2.4 and still had the same issue. I'm not sure if this got accidentally removed in a later update seeing as the issue is closed. Using the work around provided by @agnosticdev seemed to work so I will continue with that for now. Thanks!

@RoryCombe
Copy link

I ran into this same issue today using the latest release 0.4.2. I was trying to add to a relation on a plain object, not a query:

ParseReact.Mutation.AddRelation({
  className: "_Role",
  objectId: "r123"
}, "users", someUserObj)

@agnosticdev's workaround also works for me, thanks!

@yogurt-island-331
Copy link

@andrewimm I think parse-react/react-native also has this issue, so changing the code according to @agnosticdev works perfectly, maybe we could get another commit for parse-react/react-native? Thanks a bunch!

@ShayMatasaro
Copy link

@andrewimm it looks like the latest code still has this issue?
...
SubscriptionManager.queriesForFields(
changes.latest.id.className,
changes.fields
....
I am seeing it on version 0.5

@ShayMatasaro
Copy link

the above fix worked for me , for
ParseReact.Mutation.Add

@AndreiCalazans
Copy link

I'm having the same issue.
screen shot 2017-08-13 at 12 17 13

const eventId = { objectId: Parse.User.current().id, className: '_User' };

ParseReact.Mutation.Set(eventId, newData) .dispatch() .then(() => { that.props.loading(false); browserHistory.push('/'); }, (err) => { console.log(err); that.props.loading(false); });

Are there any solutions for this ?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants