How to change the default delimiter of Handlebars.js? - laravel

I need to use handlebars.js and I also use Blade template engine from Laravel (PHP Framework). The tags {{}} conflict with blade's placeholders that are exactly the same.
How can I change those {{var}} to something like <% var %> ?

Although it may be true that you can't configure Handlebars' expression delimiters, that's not the only way to resolve the conflict between Handlebars and Blade. Blade provides syntax that allows you to avoid the conflict by designating what should be passed on to Handlebars. (This is fitting, since Blade created the conflict to begin with, and it's necessary, since Blade is processing the template before Handlebars ever sees it.) Just prepend # before the curly braces that you want Blade to ignore and pass as-is to Handlebars. Here's a very short snippet of a much larger example:
...
<link
rel="stylesheet"
type="text/css"
href="{{ asset("css/bootstrap.theme.3.0.0.css") }}"
/>
<title>Laravel 4 Chat</title>
</head>
<body>
<script type="text/x-handlebars">
#{{outlet}}
</script>
...
{{outlet}} will be passed to Handlebars, but {{ asset("css/bootstrap.theme.3.0.0.css") }} will be handled by Blade.

I created handlebars-delimiters on GitHub / npm to make it easy to use custom delims with Handlebars.
var Handlebars = require('handlebars');
var useDelims = require('handlebars-delimiters');
var a = Handlebars.compile('{{ name }}<%= name %>')({name: 'Jon'});
console.log(a);
//=> 'Jon<%= name %>'
// Pass your instance of Handlebars and define custom delimiters
useDelims(Handlebars, ['<%=', '%>']);
var b = Handlebars.compile('{{ name }}<%= name %>')({name: 'Jon'});
console.log(b);
//=> '{{ name }}Jon'
The idea for the compile function came from https://stackoverflow.com/a/19181804/1267639
Suggestions for improvement or pull requests are welcome!

Instead of changing the delimiters you can create files with your handlebars templates in without the .blade extension. Just include these files in your blade template. E.g
Blade Template File - template.blade.php
#extends('master.template')
#section('content')
#include('handlebars-templates/some-template-name')
#stop
some-template-name File - some-template-name.php
<script type="text/x-handlebars" data-template-name="content">
<div>
<label>Name:</label>
{{input type="text" value=name placeholder="Enter your name"}}
</div>
<div class="text">
<h1>My name is {{name}} and I want to learn Ember!</h1>
</div>
</script>

I've made this function.
Hope it can be useful for someone..
/**
* change the delimiter tags of Handlebars
* #author Francesco Delacqua
* #param string start a single character for the starting delimiter tag
* #param string end a single character for the ending delimiter tag
*/
Handlebars.setDelimiter = function(start,end){
//save a reference to the original compile function
if(!Handlebars.original_compile) Handlebars.original_compile = Handlebars.compile;
Handlebars.compile = function(source){
var s = "\\"+start,
e = "\\"+end,
RE = new RegExp('('+s+'{2,3})(.*?)('+e+'{2,3})','ig');
replacedSource = source.replace(RE,function(match, startTags, text, endTags, offset, string){
var startRE = new RegExp(s,'ig'), endRE = new RegExp(e,'ig');
startTags = startTags.replace(startRE,'\{');
endTags = endTags.replace(endRE,'\}');
return startTags+text+endTags;
});
return Handlebars.original_compile(replacedSource);
};
};
//EXAMPLE to change the delimiters to [:
Handlebars.setDelimiter('[',']');

This is not possible with "standard" Handlebars. https://github.com/wycats/handlebars.js/issues/227

"If you need to display a string that is wrapped in curly braces, you may escape the Blade behavior by prefixing your text with an # symbol"
#{{varname}}
Hope it helps!

I used and updated the source code of user1875109 and now it works with Handlebars v3.0.3:
/**
* change the delimiter tags of Handlebars
* #author Francesco Delacqua
* #param string start a single character for the starting delimiter tag
* #param string end a single character for the ending delimiter tag
*/
Handlebars.setDelimiter = function(start,end){
//save a reference to the original compile function
if(!Handlebars.original_compile) Handlebars.original_compile = Handlebars.compile;
Handlebars.compile = function(source){
var s = "\\"+start,
e = "\\"+end,
RE = new RegExp('('+s+')(.*?)('+e+')','ig');
replacedSource = source.replace(RE,function(match, startTags, text, endTags, offset, string){
var startRE = new RegExp(s,'ig'), endRE = new RegExp(e,'ig');
startTags = startTags.replace(startRE,'\{');
endTags = endTags.replace(endRE,'\}');
return startTags+text+endTags;
});
return Handlebars.original_compile(replacedSource);
};
};
//EXAMPLE to change the delimiters to [:
Handlebars.setDelimiter('[',']');

There is an option to tell template engine for not parsing certain part of code and treat it as plain text.
Find the following ways to do it, hope it helps somebody.
In blade template engine (laravel) you can use #verbatim Directive. So that you dont have to add # to every variable.
Example :
#verbatim
<div class="container">
Hello, {{ name }}.
</div>
#endverbatim
Similarly for twig template engine (symfony) you can block the whole code by using
{% verbatim %}
<div>
My name is {{name}}. I am a {{occupation}}.
</div>
{% endverbatim %}

Related

Laravel Blade adding double quotes around HTML attributes

I'm writing a custom Laravel Helper that generates the img HTML tag dynamically (I use this to generate the img srcset and size attributes, because I use a CDN).
But when returning the generated string, double quotes are added around the attributes.
Spaces in attribute values are also broken into smaller attributes.
<img src=""https://ik.imagekit.io/sdqrv2ex9bq/Rosa_de_Saron/cremacao_slide.jpg?ik-sdk-version=php-2.0.0"srcset="https://ik.imagekit.io/sdqrv2ex9bq/Rosa_de_Saron/tr:w-768:/cremacao_slide.jpg?ik-sdk-version=php-2.0.0" 768\w,https:="" ik.imagekit.io="" sdqrv2ex9bq="" rosa_de_saron="" tr:w-1366:="" cremacao_slide.jpg?ik-sdk-version="php-2.0.0" 1366\w"="" alt="Pessoa com urna funerária" width="1366" height="768">
This is my Helper:
function image_cdn($path, $sizes=[], $transform=[]){
//CRIA OBJETO DO SDK
$image = new ImageKit(
env('IMAGEKIT_PUB_KEY'),
env('IMAGEKIT_PRIV_KEY'),
env('IMAGEKIT_ENDPOINT')
);
//ADICIONA URL DEFAULT
$tagImg = ' src="'.$image->url([
'path'=>$path,
'transformation'=>$transform
]).'"';
//ORDENA OS INTENS DO ARRAY
$sizes = Arr::sort($sizes);
//LOOP PARA GERAR CADA SIZE ENVIADO (SE HOUVER)
foreach($sizes as $size){
//GERA URL DA IMAGEM COM A TRANSFORMAÇÃO DO WIDTH
$imageSet[] = $image->url([
'path'=>$path,
'transformation'=>[
['width'=>$size],
$transform
]
])." $size\w";
//GERA O ATRIBUTO SIZES
$imageSize[] = "(max-width: $size\px) $size\px";
}
//SE FORAM SIZES PARA A IMAGEM ADICIONA ELES NA TAG GERADA
$tagImg .= isset($imageSet) ? 'srcset="'.implode(',',$imageSet).'"' : '';
//RETORNO
return $tagImg;
}
The Helper call:
<img {{ image_cdn('cremacao_slide.jpg',[768,1366]) }} alt="Pessoa com urna funerária" width="1366" height="768">
Your function is returning a fully built attribute that you want to display as-is. The {{ }} blade syntax, however, will escape your special characters.
You need to use the {!! !!} syntax to print your value without blade escaping it.
<img {!! image_cdn('cremacao_slide.jpg',[768,1366]) !!} alt="Pessoa com urna funerária" width="1366" height="768">
On a complete side note, I see your function is using the env() function directly. The env() function should only be used inside the config files, and the config values should be accessed inside your function. As it is written right now, this code will break if you ever cache your config (ex: in production).
The other option, if you want to keep using the {{ }} escaped echo syntax, is to put your string into an HtmlString object. The e helper method, which escapes the strings for the echos, checks if what is being passed is Htmlable and will directly return the call to toHtml on it instead of escaping the content:
function returningSomeHtml(...)
{
return new Illuminate\Support\HtmlString(...the HTML Content...);
}
{{ returningSomeHtml(...) }}
I solved the problem using Blade Components, so it's working fine now.
Since the attribute value is added directly to the attribute's double quotes, the problem does not occur.
<img src="{{$imageDefault}}" {{$slot}}
#if ($imageSet)
srcset="{{$imageSet}}"
sizes="{{$imageSizes}}"
#endif

Comment out a part of Vue template element

Sometimes it is needed to comment out some element attribute without having to remember it in order to restore it quickly after some tests.
Commenting out whole element is achievable with HTML commenting syntax
<div>
<!-- <h2>Hello</h2> -->
<span>hi</span>
</div>
However this won't work with a single attribute (causes rendering error)
<my-comp id="my_comp_1"
v-model="value"
<!-- :disabled="!isValid" -->
#click="handleClick">
</my-comp>
The best approach I could see and used before was to make a tag backup by copying whole element and settings v-if="false" for it (or comment out whole copied element) and continue to experiment with original one
I don't think you can put an HTML comment inside a component tag, for much the same reason you can't put comments inside an HTML element opening tag. It's not valid markup in either situation. I think the closest you could come would be to place the comment in the quotes:
:disabled="// !isValid"
Which would have the same effect as:
:disabled=""
Depending on whether your component can handle that value being missing, that might fit your needs.
Prefix the attribute value with data- or Wrap with data attribute.
<my-comp id="my_comp_1"
v-model="value"
data-:disabled="!isValid"
data-_click="handleClick"> # `#` could not be used
</my-comp>
or
<my-comp id="my_comp_1"
v-model="value"
data='
:disabled="!isValid"
#click="handleClick">
'>
</my-comp>
I'll with the attribute set to something like data-FIXME.
I got these solutions to work. I thought of solution 1.
Starting code:
<div
v-for="foo in foos"
:key="foo.id"
#click="foo.on = !foo.on /* JavaScript comment. */"
>
<label>
{{ foo.name }} {{foo.on}}
</label>
</div>
The Vue directive HTML attribute that needs to be disabled: #click="foo.on = !foo.on"
How the final div tag will run:
<div
v-for="foo in foos"
:key="foo.id"
>
Solutions 1 and 2 keep the disabled attribute inside its tag. I didn't find a good way to make a "raw string". To keep the attribute in the tag, the outer and inner quotes must be different.
sol. 1: I made a new v-bind attribute (:lang) to put the disabled attribute in.
:lang='en /* #click="foo.on = !foo.on" */'
Sol. 2: Pick a Vue directive. Put the attribute in.
v-for="foo in foos /* #click='foo.on = !foo.on' */"
Solutions 3 and 4 put the attribute outside the tag.
Sol. 3:
<div v-if="false">
#click="foo.on = !foo.on"
</div>
Sol. 4: <!-- #click="foo.on = !foo.on" -->
One way to remove/hide component attributes is to create a custom directive for it.
Let's say you create a directive called v-hide and put it in your component as:
<my-comp v-model="value" #click="handleClick" v-hide :disable='true'></my-comp>
And the output would be:
<my-comp v-model="value" #click="handleClick"></my-comp>
Here is a working example:
Vue.component ('my-component', {
template: `<p> A custom template </p>`
})
Vue.directive('hide', {
inserted: function (el) {
console.log('el before hide', el)
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
console.log('el after hide', el)
}
})
new Vue({
el: '#app',
data () {
return {
someValue: 'Hello'
}
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<my-component v-model='someValue' v-hide :disable='true'></my-component>
</div>

Change interpolation brackets - Angular2

I want to use Laravel Blade and AngularJS.
Is some way to change interpolate sintax, change {{text}} for [{text}] or somthing like that?
I already change all components.ts files adding the line:
interpolation: ["{[", "]}"],
but, where I write blade, app breaks...
Thanks a lot everybody ;)
You can define your Blade content tags in your routes.php file:
Blade::setContentTags('<%', '%>');
Blade::setEscapedContentTags('<%%', '%%>');
EDIT: You can add # in front of the brackets, so Blade won't render it.
#{ var }
or you can pass the directive for blade not to render part of the HTML using #verbatim keyword.
#verbatim
<div>
{{ var }}
</div>
#endverbatim

Is it possible to use vue-specific directives in localized text?

I just started using vue-i18n and tried to use the v-on-directive (shorthand: #) in my language specific text.
What i tried to do:
// locale definition
let locale = {
en: {
withEventListener: 'Some HTML with <a #click="onClickHandler">event handling</a>'
}
}
and the vue template:
<!-- vue template be like -->
<p v-html="$t('withEventListener')" />
This doesn't throw an error but unfortunately it does not get evaluated by vue-js either. This would result to Plain-HTML like:
<p>
Some HTML with <a #click="onClickHandler">event handling</a>
</p>
So my question is if there is a way to make Vue 'evaluate' the text and thus 'translate' the directives within the text.
You can use Vue.compile to do something like this if you are including the standalone build script. I'm not familiar with vue-i18n, but this might put you on the right path.
Note that I had withEventListener to wrap it in a div because of the rules around templates.
let locale = {
en: {
withEventListener: '<div>Some HTML with <a #click="onClickHandler">event handling</a></div>'
}
}
const res = Vue.compile(Vue.t("withEventListener"));
Vue.component("internationalized", {
methods:{
onClickHandler(){
alert("clicked")
}
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
new Vue({
el:"#app"
})
With the template
<div id="app">
<internationalized></internationalized>
</div>
Working example.

How to remove the style tag using asp.net

I want to remove all style attribute in html tags using asp.net...
string source=#" <div style="font-size: 12pt;"> Hello world</div> <style id=fll margin:19px auto;text-align:center"></style>";
I want the result like this:
<div>Hello world </div>
For that i am using,
string expn =#"(?i)<(table|tr|td)(?:\s+(?:""[^""]""|'[^']'|[^""'>])*)?>";
return System.Text.RegularExpressions.Regex.Replace(source, expn, string.Empty);
I dont know which one is using,
Tell me the query what i have to use for this one....
This should work (though I don't understand the style tag at the end of your example):
string source="<div style=\"font-size: 12pt;\"> Hello world</div>";
string pattern = "style=\".*\"";
string result = Regex.Replace(source, pattern, "");

Resources