Laravel Blade adding double quotes around HTML attributes - laravel

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

Related

Convert foreach loop into array using laravel5

#foreach($users as $user)
$users[] = $user->name;
#endforeach
I want to get the output like this.
['X', 'Y', 'Z', 'C'];
Note: i need this because i have to use this in JavaScript function.
First of all, you can't "turn a foreach loop into an array", you would use that foreach loop to get an array as outcome. In this case I wouldn't go with a foreach approach, there are some methods that can help you cleaning out your code a bit.
You have two options depending on the type of the $users variable, pluck() or array_column():
// $users is a collection
json_encode($users->pluck('name'));
// $users is an array
json_encode(array_column($users, 'name'));
The json_encode() is highly recommended (as the comments pointed out) if you are going to use that output in your javascript. Now you can just send it in a respond and use it as a normal JSON.
In case you print the resulting variable using Blade, remember you need to use {!! !!}, otherwise, if you use {{ }} you would get unwanted scaped characters, since it uses htmlspecialchars() function under the hood.
Hope this helps you.
I recommend You should perform this action in your controller only, and then pass it to your view as
$userNames=implode(",",array_column($users,'name'));
return view('your_view',['userNames'=>$userNames]);
Then split it in your js as
var names="{!! $userNames!!}";
var names= names.split(",");
Collections will automatically be converted to json when you try to echo them.
The reason you're seeing " is because using {{ }} will automatically escape strings for your protection. You can prevent this by using {!! !!} instead.
Try something like this:
<script>
var data = '{!! $users->pluck('name') !!}';
console.log( JSON.parse(data));
</script>
Hope this helps!

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

laravel & blade templating #section error

I want to display full name as title:
#section('title', ['title' => $userdetail->fullName])
I have used the above code and it shows the error exception of string to object conversion.
modify your #section to this
#section('title', {{$userdetail->fullName}})
#section('title', $userdetail->fullName)
You don't need to specify it as an associative array, just put variable and section will be the value of this variable
Do like this --
#section('title', "$userdetail->fullName")
Wrap the second parameter inside double quotes since it renders it automatically renders a variable and normal text, whereas single quotes only render text and not variable.
And remember that you cannot use blade echo {{ }} inside a blade syntax.
like - #section('title', {{ $userdetail->fullName }})

Laravel blade #include into a Javascript variable?

In a Laravel 5 blade template I have a <script> section.
In this section I need to set a variable to a string that is coming from another blade template.
I tried something like :
<script>
var a = "#include 'sometext.blade.php' ";
</script>
but this obviously doesn't work.
Also, the included blade can contain both single and double quotes, so these need to be escaped somehow, or the Javascript will not be valid.
Any ideas?
Ended up needing similar functionality when working with DataTables, and the additional actions HTML needs to be injected after the fact via jQuery.
First I created a helper function with this (from Pass a PHP string to a JavaScript variable (and escape newlines)):
function includeAsJsString($template)
{
$string = view($template);
return str_replace("\n", '\n', str_replace('"', '\"', addcslashes(str_replace("\r", '', (string)$string), "\0..\37'\\")));
}
Then in your template you could do something like:
$('div.datatable-toolbar').html("{!! includeAsJsString('sometext') !!}");
to include the sometext.blade.php blade template with escaping of quotes and removal of newlines.

How to change the default delimiter of Handlebars.js?

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 %}

Resources