Adding Link for Button Action

2019-08-19 02:42发布

问题:

I recently started a new site with Apostrophe CMS, and one of the features in the project will be extending apostrophe-events to have a list of "registered" users who are associated with each event. I was able to add a new joinByArray column to the apostrophe-events module, and it works correctly when editing events.

Now, I'm trying to add a Register button to the apostrophe-events-pages module, so that users can register for the event from each event's page. I currently have a working API endpoint available, which I created using this code:

(In file lib/modules/apostrophe-events-pages/index.js)

module.exports = {
    construct: function(self, options) {
        self.route('get', 'register', function(req, res) {
            // Validate things with the launder module
            var name = self.apos.launder.string(req.body.name);
            // Deliver a JSON response
            return res.send({ status: 'ok', moreInfo: 'something' });
        });
    }
};

That endpoint works as expected, but I'm stuck on adding a button with a link to the correct action on the front end. I created a button that looks correct in the show.html overwrite that I created, with the following code:

(In lib/modules/apostrophe-events-pages/views/show.html)

{{ buttons.minor('Register for Field Trip', { action: 'register' }) }}

I'm not sure how I can add a link to the register action. I tried adding this code to the same index.js file as above:

(In lib/modules/apostrophe-events-pages/index.js)

self.registerEvent = function() {
    var res;
    self.api('register', {}, function(result) {
        res = results;
    });
};

var superBeforeShow = self.beforeShow;
self.beforeShow = function(callback) {
    self.link('register', self.registerEvent);
    return superBeforeShow(callback);
};

But when I access the event page, an error happens that says self.link is not a function. Should I be putting the link code elsewhere?

Thanks!

回答1:

I'm the lead architect of Apostrophe at P'unk Avenue.

First, you're having difficulty because you're trying to call frontend javascript APIs like link from the index.js file of your module, which is back-end node.js code.

You will need to push an always.js javascript file to the browser. You can call this in your module's index.js:

self.pushAsset('script', 'always', { when: 'always' });

Then populate your module's public/js/always.js file with your frontend code.

Second, the self.link code you're probably looking at is really only intended for something that is "in context," for instance to a particular dialog box. You are looking to bind to any click on a button with a particular data attribute. For that, you could write:

apos.ui.link('register', 'event', function($el, _id) { ... }

In your always.js, and this code will respond to anything with an action named register-event:

{{ buttons.minor('Register for Field Trip', { action: 'register-event' }) }}

But this is just a convenient way to write a jQuery delegated event handler. You could also just write:

$('body').on('click', '[data-register-event]', function() { ... })

You should wrap your always.js code in a DOM Ready function:

$(function() { ... })

As for calling self.api, that is pretty convenient, and you can look into subclassing apostrophe-context to get access to it, but you can also just build the URL yourself and invoke our jsonCall jQuery plugin from your always.js:

$.jsonCall('/modules/your-module-name/register',
  { ... data ... },
  function(result) { ... }
);

Please check out the tutorial building a contact form, which includes material on how to push an always.js file from the public/js folder of your module as an asset and so on.

That tutorial also demonstrates the technique of using a custom apostrophe widget type to provide a home for your frontend code, which I generally recommend. It gives you access to self.api and so on.