A few subtleties of using jade in Meteor projects

Some time ago I had to plunge into Meteor. Despite the fact that I do not like javascript, coffeescript is even more infuriating, and node.js infuriates me, Meteor very quickly gained my recognition and love. I did not work with it until version 1.0+, as far as I know, there were a lot of horrors, but now, for me personally, this is a very convenient tool for small interactive projects. Therefore, I really want to share what can facilitate the use of this tool to other people.

My experience with Meteor is not so great as to take and start something difficult to sort through. However, I came across some things, banged my head about them and found some solutions. And in this article I want to share my observations / tips on working with jade in Meteor. Unfortunately, with him everything is not as great as with a pure jade.

In my projects I use the mquandalle: jade package, and it has a number of unpleasant features. Custom template helpers do not work quite as you would expect. The standard syntax implies that we simply take and call the helper with a regular string, if it is used by itself. Or we frame in # {} if it is used in a string with something. Here is an example (all coffeescript code):


        ifHelper: ->
            return true
        plainTextHelper: ->
            return 'Just some value'


		if ifHelper
			.some-class #{someHelper}

Everything works fine, until you try to pass the value to the helper to get the value of the string. And this is required, and quite often. If you write # {someHelper someval}, the output will get the string '# {someHelper someval}'. Perhaps someone will immediately decide that since the Jade option does not work, then you should use the standard template syntax. But, for example, I really do not like the use of non-native things in the syntax, and therefore for a long time I persistently searched for how to make the construction I need on the jade syntax work. The answer is no way. At least at the time of writing, I have not found a recipe anywhere. I had to sacrifice the principle and write not very beautifully {{someHelper someVal}}.

However, if you need to return text from the html helper (and this happens), then you need to use triple curly braces {{{someHelper someVal}}}. Otherwise, the html code will be secure, i.e. displayed in the form of '& code;'

Instead of if not, you need to use unless. But there are no normal js conditions inherent in this template engine in free life in the meteor edition. Therefore, pretty quickly I had a file in which I put the functionality I need for the template engine and drag it between projects. While it looks like this:

UI.registerHelper 'print', (obj)->
  console.log('TEMPLATE DEBUG: type:', typeof(obj), 'val:', obj)
UI.registerHelper 'equal', (obj1, obj2)->
  return obj1 == obj2
UI.registerHelper 'notequal', (obj1, obj2)->
  return !(obj1 == obj2)
UI.registerHelper 'collectionIsEmpty', (col)->
  error_flag = false
  try col.fetch()
  catch error
    obj = col
    error_flag = true
  if !error_flag
    obj = col.fetch()
  return !obj.length

If someone does not know, then the UI.registerHelper function registers a global helper, which is available in all templates. As for the functions themselves, the first is used to debug template variables. Sometimes it’s useful to understand what lies in a variable and why it does not work the way I expect. Just write:

{{print someVar}}

… or:

{{print someHelper}}

... and we get the output to the console, where we see the type and value.

The second and third helpers are adapting the simple conditions of a template from Django, my favorite web framework (well, where is it without ads?)

The last helper is used to test the ability to iterate (iterate) a collection. In order not to doubt whether I returned .fetch () from the collection, or whether it is in its pure form, the helper is slightly complicated.

Also, in working with templates, I struggled for a long time about the syntax of each. When we call each, we change the context of the template, and this does not point to the scope of the template, but to the scope of the iterable object.

	.some-class #{this.title}
		each MyBlogPostCollection
			h1 #{this.title}

In the first case, .title will be either a template helper with that name, or a property from a data object if you use iron-router. In the second, .title will be taken from the MyBlogPostCollection collection object. By the way, this can not be written to refer to properties, it’s quite simple # {title}

But this is all quite simple, and now actually what I struggled with. If in each we need to access the object from the parent context, then it is used ... (two points), and there is no need to write this, its parser will not gobble up. As a result, these are the following, not always obvious constructions:

{{someHelper ../../..}}

Within the parent context, if required, you can also directly access properties. i.e.:

{{someHelper ../../title}}

I also honestly banged my head trying to dynamically put down a class for an element. Although, perhaps, it is only up to me that some things get so tight.

.contacts(class="{{#if isPdf}} border-radius-pdf {{/if}}")

Well, if the same is required with the helper, then:

.contacts(class="{{#if isPdf}} {{border-radius-pdf  someVal}} {{/if}}")

And yes, a small remark, the complete if-else construct looks like this: {{#if <...>}} {{else}} {{/ if}} that is, else does not have #, which, in my opinion look is not logical.

A pure jade if-else looks simple:

		.some value
		.another value

But remember that the condition cannot be added to if.

Of the intricacies of using jade, this is probably all I can tell right now. When I sat down to write an article, I wanted to share a few tricks not only in working with templates, but also in processing form data, loading images, but after writing about jade, I decided not to throw everything in a heap. Just the other day I solved a non-trivial task - I learned to take a screenshot of the application with user data. Perhaps some of this will be interesting - leave comments, if there is a demand - I will write.

Also popular now: