0

I am trying to create a custom apostrophe-images-widgets layout for my site. I have currently created a project-level override for the html template in the lib/modules/apostrophe-images-widgets/views/widget.html. The issue I have is whenever I choose an image to place into my custom area, apos.attachments.url is called twice: once with the image I selected and again with an undefined attachment.

My custom widget.html looks like so:

<a href="/"><img class="logo" src="{{ apos.attachments.url(image.attachment, { size: 'full'}) }}" /></a>

My entire lib directory looks like so:

custom lib

My app.js is setup with the default configuration.

My custom layout.html is referencing the images like so:

{{
    apos.area(data.page, 'web-logo', {
        widgets: {
            'apostrophe-images': {
                size: 'full'
            }
        }
    })
}}

I am not sure what other inforamtion I can give you, other than the exception is thrown here in the apostrophe-attachments/lib/api.js:

self.url = function(attachment, options) {
  options = options || {};

  // THROWS ERROR AT `attachment._id`
  var path = '/attachments/' + attachment._id + '-' + attachment.name;
  if (!options.uploadfsPath) {
    path = self.uploadfs.getUrl() + path;
  }
// other code
}

I am not too sure where to even look as to find a solution... Anything else I can provide, please let me know.

I have not overridden the index.js of apostrophe-images-widgets or apostrophe-images

the exact error I get is long, but here is the start of the stacktrace

TypeError: Cannot read property '_id' of undefined

Not very helpful, but that's it.

Thanks for reading and any help given!

Carson
  • 1,169
  • 13
  • 36

1 Answers1

1

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

If you take a look at widgetBase.html in the apostrophe-images-widgets module, you'll find that image is not passed directly to the template. Instead Apostrophe always passes data to the template as properties of a data object. And in the case of a widget, the data associated with the widget is passed as data.widget.

The images widget in particular extends the pieces widget, which can potentially display more than one item. So there is a join in its schema, and you can find the actual pieces (the images) in the array property data.widget._pieces.

One last wrinkle: sometimes these joins have "relationship properties" of their own, in this case the cropping coordinates (if any), which are separate from the actual image. So each entry in the array is actually an object with an item property (the image) and other properties relating to the crop. Therefore one extra line of code is needed to fetch the actual item from each entry in the array.

Here is a working version of your code:

{%- for entry in data.widget._pieces -%}
  {# Works whether there's a relationship in the join or not. Normally there always #}
  {# is for slideshows, but just in case someone really hates cropping... -Tom #}
  {%- set image = entry.item or entry -%}
  <a href="/"><img class="logo" src="{{ apos.attachments.url(image.attachment, { size: 'full'}) }}" /></a>
{%- endfor -%}

Hope this is helpful!

P.S. One more thing: do not use hyphens in your area names. You'll note that Apostrophe is displaying a warning about it. You may useCamelCase if you wish.

Tom Boutell
  • 7,281
  • 1
  • 26
  • 23