简体   繁体   中英

How to refresh client side value when meteor method throws an error?

I wrote a Meteor method for changing an object. Only the owner of the object should be able to edit properties.

The method thus checks for a match of the current user and the object owner. If it doesn't match, the method throws an exception with the cause.

This approach works, as the change does not hit the collection and the error object is returned to the client.

Nevertheless the edited property is not updated to reflect it's actual value. How can I trigger refreshing the value?

Additional info: I am using React on the frontend; the object is not updated explicitely in the frontend code (so the method seems to be run on the client side, too).

Some code (simplified, naming changed, obvious errors might not be in the original ;)

Client side:

  saveCommentChanges(updatedComment) {
    Meteor.call('comment.updateComment', updatedComment, function (error, result) {
      if (error && error.error === "not-authorized") {
            Session.set("errorMessage", "You are only allowed to change own comments.");
      }
    });
  }

Server Side:

if (Meteor.isServer) {  
  Meteor.methods({
    'comment.updateComment'(comment) {
    check(comment, Object);

    origComment = Comments.findOne(comment._id);

    if (origComment.user != this.userId) {
      console.log('user does not match');
      throw new Meteor.Error('not-authorized');
    }

    let res = Comments.update(
      {'_id': comment._id},
      {$set: {date: comment.date,
          comment: comment.comment}
      }, {removeEmptyStrings: false});
    }
  }

To refresh in the client side after update:

  1. Make sure you publish the data on the server and then add to constructor in controller - this.subscribe('Comments'); See the example below in AngularJS
  2. Once the server updates, the comments should update. You may also need to run meteor remove autopublish for the front end to update correctly. The meteor server prompted me to do this

In your case, the comments won't be filtered and you can filter the update based on the comment ID and the user. If no already existing comment is found, then the update will not work and you can catch throw an error.

  if (Meteor.isServer) { 
// This code only runs on the server
      Meteor.publish('comments', function publishComments() {
        return Comments.find({});
      });
  }

  Meteor.methods({
    'comment.updateComment'(comment) {
    check(comment, Object);

    origComment = Comments.findOne(comment._id);

// option 1
    if (origComment.user != this.userId) {
      console.log('user does not match');
      throw new Meteor.Error('not-authorized');
    }

// keep the same update here

// option 2
    let res = Comments.update(
       { '_id': comment._id,'user': origComment.user},
      {$set: {date: comment.date,
          comment: comment.comment}
      }, {removeEmptyStrings: false});
      return res;
    }
);

imports/component/stocks/stocks.html

<button type="submit" class="btn btn-success btn-sm m-2" 
ng-hide="{{$ctrl.currentUser === null}}"
ng-click="$ctrl.buyStock(stock.name, 1)">
   Buy 1 Share
</button>

imports/component/stocks/stocks.js

import angular from 'angular';
import angularMeteor from 'angular-meteor';
import template from './stocks.html';

import { Meteor } from 'meteor/meteor';
import { Stocks } from '../../api/Stocks.js';
import { UserStocks } from '../../api/UserStocks.js';

class StocksCtrl {

  constructor($scope) {
    $scope.viewModel(this);

    this.subscribe('stocks');
    this.subscribe('userStocks');

    // Return the data mostly right now
    this.helpers({
      currentUser() {
        return Meteor.user();
      },
      stocks() {
        const selector = {};
        // Show newest tasks at the top
        return Stocks.find(selector, {
          sort: {
            name: 1
          }
        });
      },
      userStocks() {
        return UserStocks.find({});
      }
    })
  }

  buyStock(stock, amt) {
    console.log("Buying stock processing...");

    // ADD TO UserStock
    Meteor.call('userStocks.buy', stock, amt, function(error, result) {
      if(error){
        console.log(error.reason);
        return;
      } 
      // log to console
      console.log("UserID: " + Meteor.userId() + "\n Username: " + Meteor.user().username 
        + "\n Message: Purchase of " + amt + " shares of " + stock + " was successful.");

      // alert the user
      alert("Purchase of " + amt + " shares of " + stock + " was successful.");
    });
    console.log("Buying stock complete.");
  }

}

export default angular.module('StocksApp', [
  angularMeteor
])
.component('stocksApp', {
  templateUrl: 'imports/components/stocks/stocks.html',
  controller: ['$scope', StocksCtrl]
});

imports/api/UserStocks.js

import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';

export const UserStocks = new Mongo.Collection('userStocks');


if (Meteor.isServer) {
  // This code only runs on the server
  // Only publish tasks that are public or belong to the current user
  Meteor.publish('userStocks', function getUserStocks() {
    return UserStocks.find({
        ownerID: { $eq: this.userId }
      });
  });
}

Meteor.methods({
  'userStocks.buy' (stock, amount) {
    // Make sure the user is logged in before inserting a task
    if (!Meteor.userId()) {
      throw new Meteor.Error('not-authorized');
    }

    // if currently exists, increase the amount by the amount purchased
    // if it does not exit, the upsert true will create/insert
    const newID = UserStocks.update(
      { ownerID: { $eq: this.userId }, stock: { $eq: stock } },
      { $setOnInsert: { ownerID: this.userId, stock: stock}, $inc: {amt: amount} },
      { upsert: true, returnNewDocument: true}
    );

    return newID;
  }
});

server/main.js

import '../imports/api/Stocks.js';
import '../imports/api/UserStocks.js';

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM