Using Meteor with Angular2/Typescript, how do I ca

2019-08-05 13:56发布

问题:

When the user adds a new entry in the client, I need to make a web service call from the server (the client-side code will not have access) and add some additional information to the data stored in MongoDB. Trying to use the standard Meteor.methods/Meteor.call pattern does not seem to work.

Do I need to listen for the click event on the "Add" button on both the server and the client? Should I raise a custom event on the client that the server reacts to? Is there a proper way to make a direct call to a server-side method? Most importantly, how do I keep TypeScript happy in all of this?

I am new to the TypeScript layer on top of Meteor and it is throwing me for loop. I have been generally following the Angular-Meteor tutorial for 2.0 but this sort of thing is not covered yet.

回答1:

Using angular2, Meteor and Typescript, what works is to chain the Meteor.methods.

First on the client, in response to a button click ...
Meteor.call('importCsv',id,function(error,result) { ...

In collections/methods folder or similar, I define the method as follows:

Meteor.methods({
 'importCsv': function(id) {
    console.log('importCsv method on client');
    Meteor.call('importCsvServer',id);

 }

});

In server/ folder, a file includes the method as follows

Meteor.methods({
'importCsvServer': function(id) {

....

In server/main.ts I import the collections/methods/filename. In client/app.ts I import the same thing. The client Meteor.call successfully calls the first method which then calls the second one in the server/ folder.

My goal is to have a bunch of processing on the server initiated by the client. When I had the function calls in the method defined in collections/methods imported into both the client and server, it resulted in compiler errors.

Angular2-Meteor issue 74



回答2:

Yes, you can call directly from the server to the web service in order to receive data. I am not so sure how you did for the Meteor.methods/Meteor.call and say it did not work. But basically, the idea is client will click the button and then button will trigger a method on the server. The server method then will call the web service and return the data.

Some example code could be:

Template['template'].events({
    'click .getData': function(event: any) {
        Meteor.call('serverMethod', function(err, res) {
            if (err) {alert(err);}
            else { ... }

        )
    }
});

The tricky part for new comer when calling the rest is you need to use aysnc calling in order to return the data to client. We normally make helper function for that

    public static get(url: string, headers: any): any {
        var httpCall  = Meteor.wrapAsync(HTTP.call);

        var result = httpCall('GET', url, {headers: headers});

        if (result.statusCode == 200) {
            try {
                var res = JSON.parse(result.content);

                return res;
            } catch(err) {
                return result.content;
            }   
        }

        return null;    
    }

And call the helper like this

public static serverMethod(username: string, password: string): any {
    var response = RestService.get(query.url, query.header); 
    return response;
}

This way, the res in the client code above will get the result.

I actually dropped the Angular 2 for the lack of documentation, but stay with Typescript for my system because I can wrap all the meteor call inside the Typescript class, as you can see in my example, serverMethod is in the typescript function format, not in meteor way like Meteor.methods({....}), which is really good for now

Typically, this is a class in my server folder

// server/rest.service.ts
declare var RestService: any;
RestService = class RestService {

    methodMap = {
        "getFromRest": RestService.get,
        "postToRest": RestService.post,
    };

    constructor() {
        var abstractService = new AbstractService();
        abstractService.registerMethod(this.getClassName(), this.methodMap);        
    }

    getClassName(): string {
        return this.constructor.toString().match(/\w+/g)[1];
    }

    //------------------------------------------------------------------------------------
    // Helper methods
    //------------------------------------------------------------------------------------
    public static get(url: string, headers: any): any {
        var httpCall  = Meteor.wrapAsync(HTTP.call);

        var result = httpCall('GET', url, {headers: headers});

        if (result.statusCode == 200) {
            try {
                var res = JSON.parse(result.content);

                return res;
            } catch(err) {
                return result.content;
            }   
        }

        return null;    
    }

I have a class to map the typescript service to the meteor method

// server/abstract.service.ts
declare var AbstractService: any;
AbstractService = class AbstractService {
    constructor() {}

    public registerMethod (scopeName: string, methodMap: {[key:string]:any}) {
        var scopeMap: {[key:string]: any} = {};

        for (var key in methodMap) {
            scopeMap[scopeName + '.' + key] = methodMap[key];
        }

        Meteor.methods(scopeMap);
    }