How to keep HAML from reordering words in the class attribute? - haml

HAML and ractive.js seem to play well together (if you don't mind not indenting the contents of a mustache section), though I have found one problem I can't solve.
When I do this:
.like{ class: "{{#if like}}active{{/if}}" }
...
I get this:
<div class='like like}}active{{/if}} {{#if'>...</div>
It appears that the HAML parser is assuming that word order doesn't matter inside of a class declaration, and is messing with my string (though I can't imagine why), but in this case I need that string to be preserved!
I know I could use plain html, but it gets quite messy when there are many nested tags.
Any ideas?

I figured it out...
If I change it from this:
.like{ class: "{{#if like}}active{{/if}}" }
to this:
%div{ class: "like{{#if like}} active{{/if}}" }
It works fine.

Related

.bind vs string interpolation in aurelia

In our code base we have a mixture of the following:
attribute="${something}", attribute="${something | converter}", etc.
attribute.bind="something", attribute.bind="something | converter"
I find the latter easier to read.
The examples I'm referring to are exactly like the above; i.e., they do not add any additional string content.
I think that it's easier on Aurelia too. Am I correct?
Also, for these specific cases where no actual interpolation is
involved, is there any benefit to the first form? (other than it is
two characters less to type.)
Given the examples you have shown, I would recommend using option 2. It really isn't "easier on Aurelia," but it is more explicit that you are binding the value of that attribute to the property listed.
Original Answer Below
The benefit of the first option is when you have, for example, an attribute that accepts many values but as a single string. The most common example of this is the class attribute. The class attribute accepts multiple classes in a space-separated list:
<div class="foo bar baz"></div>
Imagine we only want to add or remove the class baz from this list based on a prop on our VM someProp while leaving the other classes. To do this using the .bind syntax, we would have to create a property on our VM that has the full list but adds or removes baz as determined by the value of someProp. But using the string interpolated binding, this becomes much simpler:
<div class="foo bar ${someProp ? 'baz' : ''}"></div>
You can imagine how this could be extended with multiple classes being added or removed. You could maybe create a value converter to do this using the .bind syntax, but it might end up with something that wasn't as readable.
I could imagine a value converter being created that might look something like this in use:
<div class.bind="someProp | toggleClass:'baz':'foo':bar'"></div>
I really think this is much less readable than using the string interpolation syntax.
By the way, the value converter I imagined above would look like this:
export class ToggleClassValueConverter {
toView(value, toggledClass, ...otherProps) {
return `${otherProps.join(' ')} ${value ? toggledClass : ''}`;
}
}
The best part is that I'm still using string interpolation in the value converter :-)
After wading through the tabs I'd already opened I found this. Although it's not quite the same thing, and it's a bit old, there's a similar thing talked about on https://github.com/aurelia/templating-binding/issues/24#issuecomment-168112829 by Mr Danyow (emphasis mine)
yep, the symbol for binding behaviors is & (as opposed to | for value converters).
<input type="text" data-original="${name & oneTime}" value.bind="name" />
Here's the standard way to write a one-time binding. This will be a bit more light-weight in terms of parsing and binding:
<input type="text" data-original.one-time="name" value.bind="name" />
I don't know if it applies to the .bind/${name} case as well as the oneTime one in the example, but perhaps if it comes to his attention he can say either way.
Given this isn't a cut and dry answer, I'll be marking Ashley's as the answer as it confirms the legibility question and provides useful information on other use cases should anyone else search on similar terms.

suppress list elements that have already been encountered

Hi I have a velocity template that I am trying to edit
it currently has a block that looks like
#foreach( $element in $myList )
$element.field1 ($element.field2) issued by $element.field ($element.field4 )
<br><br>
#end
the problem is some elements in the list are duplicated and I need to suppress the duplicates.
psuedo code for what I want is
for each element in list
if element is not in displayed
display element
add element to displayed
endif
endfor
can someone point me in the right direction?
This kind of logic (de-duplication) is probably something to be avoided in your view (Velocity) layer. Following Model-View-Controller, it would be better to have this logic managed by controller classes, leaving the Velocity template to simply render the data structure it is passed.
For example, by using a data structure such as a java.util.Set, duplicates would not be admitted and so there would be no need for the template to de-duplicate.
Personally I found Rob Harrop's Pro Jakarta Velocity a really good guide to MVC, especially Chapter 4 "Using Velocity in an MVC environment".
Have the model use a Set, have your controller code populate the set, and then the simple loop in your template code can be used as it is now.
In general, the less logic you implement in your view layer, the better. It will also make your code easier to test, so you can verify its behaviour without having to fire up the presentation components, app servers etc etc.
If there really is no choice and the logic absolutely must be written in the template, then the following implements the psuedocode presented:
#set($displayed = [])
#foreach( $element in $myList )
#if(!$displayed.contains($element))
$element.field1 ($element.field2) issued by $element.field ($element.field4 )
<br><br>
#set($ignore = $displayed.add($element))
#end
#end
Note the messiness with #set($ignore = $displayed.add($element)) - this has to be done to suppress the output from java.util.List's add() method (boolean) from being output. Another reason not to write this in template code!
Of course, you would also need to make sure that equals() is correctly implemented on the type added to the list so that the List operations - contains() and add() work correctly.
Definitely an inferior solution to the MVC approach above, but presented as an option of last resort.

Create selector dynamically from string

I've made a program that uses reflection to add Traits dynamically, and solves conflicts automatically in one predeterminated way.
It uses aliases. It's working (I think), but I have only a problem when finally adding the trait.
My program generates all the aliases for each conflicting method, and add them with the trait to the class. The problem is that I'm not able to generate the selector correctly, its generating a string instead.
For example:
I need this
TCircle # {#circleHash -> #hash}
but I'm generating this
TCircle # {'#circleHash' -> #hash}
you can see the quotes in #circleHash.
Because is a meta-program, it generates also dynamically the selector.
How I can get it without the quotes and with the #?
I need to able to do something like this
"have the selector name in string"
obj := 'SelectorDinamicallyGenerated'.
^(#obj)
and get #SelectorDinamicallyGenerated, and not '#SelectorDinamicallyGenerated'.
How can I do this?
I've tried doing like that (#obj) but it is not working (getting #obj)
I've found it.
It's
obj asSymbol
Good you found it yourself. Maybe it is just irritating that in smalltalk a symbol is a selector. It is just not the case that there is a selector class and you could do "aString asSelector". So
'foo' asSymbol => #foo
will do. If you need to generate a setter you can do
'foo' asSymbol asMutator => #foo:

Serialize C# object using JSON.NET for Dojo data-dojo-props

Dojo's dijit html5 tags use an attribte name data-dojo-props. The value is basically a JSON string without quotes around the property names and without the outermost braces.
It looks something like this.
data-dojo-props="prop1:'xyz', prop2:true, prop3: { subprop1: 1, subprop2: 'abc'}"
I'm using C# to write this out from a C# object using JSON.NET and passing in the object pointer. I found settings to leave out the property name quotes, but I can't figure out a graceful way to remove the outside braces.
For now, I'll run the string through a regex to remove them, but was wondering if someone new a better way.
I serialize each top level property separately and make it a global javascript variable. I then reference that variable in data-dojo-props. I admit it's not that elegant.
My concern with your approach above, is if the value of subprop2 contains a quote, you will get a parser error.
<script type="text/javascript">
menuData = {THE SERIALIZED JSON GOES HERE};
</script>
<div data-dojo-type="SomeWidget" data-dojo-props="menuData: menuData"></div>

Handlebars block helpers screwed up in HAML

I need to use some handlebars block helpers inside of an element's attribute. How can I get
.some.class{:class => "{{if property}} otherClass {{/if}}"}
to parse properly? Here is the compiled output as is:
<div class='class otherClass property}} some {{/if}} {{if'></div>
I've tried escaping every non-word character, trying single quotes, and adjusting the spacing, but nothing seems to fix it. I'm hoping to find a more elegant solution than just using the :plain keyword.
I've found that you need to add some character before the {{}} for Haml to accept it. For example:
%div.some.class{:class => "a{{foo}}"}
Not idea, but suites my purposes.
Actually, the trick doesn't work for anything handlebars expression that is moderately complex.
In the end I resolved this by using string literals in haml. So in the example case shown in the question. The below haml is needed, remember to close your tag, which is the last line.
\ <div class='class {{if property}} otherClass {{/if}} some '>
-# Normal haml goes here and must not start at the same indent as the above literal
\ </div>
Move all the classes in to the class attribute instead of using both the class shorthand dot notation and a class attribute.
.col-md-12.card{ class: "{{toLowerCase level_name}}-master-card" }
becomes
%div{ class: "col-md-12 card {{toLowerCase level_name}}-master-card" }
HAML 4.0.7