Search code examples
jsonpugmixins

Pug - mixin with conditional .json object


I'm trying to use a conditional (if exists an object at a external .json), but pug doesn't recognize it.

So, my json file is something like this:

{
  "portfolioItems": [object1: {
      objectA { ...
      },
      objectB { ...
      },
      "buttons": [{
        key: value
      }, {
        key: value
      }]
    }, object2: {
      objectA { ...
      },
      objectB { ...
      }], object3: {
      objectA { ...
      },
      objectB { ...
      }
    }
  }
}

Basically, I need to create an extra div for "object 1" (buttons).

mixin portfolio(css, image, title, description)
    div(class= "item " + css)
        .wrap-img
            img(src= assets + "img/home/" + image)&attributes(attributes)
        .wrap-text
            h3= title
            p= description
            if home.portfolioItems.buttons
                div.buttons
                    each val in home.portfolioItems.buttons
                        a(href= val.link, target="_blank")
                            img(class= val.className, src= assets + "img/stores/" + val.image)

div.portfolio--items
            - var projects = home.portfolioItems;
            each item in projects
                +portfolio(item.class, item.image, item.title[lang], item.description[lang])(alt= item.title[lang], title=item.title[lang])

Pug can access to "home.portfolioItems.buttons", but it can't do a conditional inside a mixin? Because I can run it outside (but I don't want it).

Thanks in advance. Sorry any mistake in english. ;)


Solution

  • Mixins have their own scope, so you'll need to pass them in an object. I'd also recommend a single options object which makes this a lot easier than tracking separate parameters, is order-independent, and is more readable too.

    Note that you can call a mixin and span multiple lines with the definition

    +portfolio({
      "css": "css",
      "image": "image",
      "title": "title",
      "description": "description",
      "items": portfolioItems
    })
    

    This is what the mixin would look like:

    mixin portfolio(options)
      div(class= "item " + options.css)
        .wrap-img
          img(src= assets + "img/home/" + options.image)&attributes(options.attributes)
        .wrap-text
          h3= options.title
          p= options.description
          if options.items.buttons
            div.buttons
              each val in options.items.buttons
                a(href= val.link, target="_blank")
                  img(class= val.className, src= assets + "img/stores/" + val.image)
    

    You could also avoid passing in all the items and pass in the buttons OR an empty array if the buttons property doesn't exist in portfolioItems:

    +portfolio({
      "css": "css",
      "image": "image",
      "title": "title",
      "description": "description",
      "buttons": portfolioItems.buttons || []
    })
    

    Which would avoid the need for the conditional test as you're guaranteed at least an empty array in the mixin:

    mixin portfolio(options)
      div(class= "item " + options.css)
        .wrap-img
          img(src= assets + "img/home/" + options.image)&attributes(options.attributes)
        .wrap-text
          h3= options.title
          p= options.description
          div.buttons
            each val in options.buttons
              a(href= val.link, target="_blank")
                img(class= val.className, src= assets + "img/stores/" + val.image)