Too many whitespaces when outputting blade variables? - laravel

A bit of background: I'm trying to create user-editable pages in a blog-style web application. The application consists of multiple pages worth of content included into one page; dynamically generated from the back-end and laid out one under the other.
Note: I am a Laravel newbie.
The content of the pages is kept in the DB; one DB record = page title + content. I retrieve all records and send them to the template:
class ContentController extends Controller {
var $current_content;
public function __construct() {
$this->current_content = Content::all();
}
public function serveContent() {
return View::make('home')->with('pages', $this->current_content);
}
}
Over in the template I iterate through the object with the freshly retrieved data and display the contents for each page:
#foreach($pages as $page)
<section class="page">
<div class="editable-page" id="{{ $page->page }}">
{{ $page->content }}
</div>
<div hidden class="editable-page-edit-mode" id="{{ $page->page }}">
<textarea class="page-edit">
{{ $page->content }}
</textarea>
</div>
<input hidden type="button" class="edit-btn" value="Edit {{ $page->page }} section"/>
</section>
#endforeach
(The textarea is for the edit mode, it contains the same content as above; except this time it will be sent back to the DB).
The problem is that when outputting the variable contents with {{ $page->content }}, an absurd amount of whitespaces seem to be introduced.
Here's how the section looks in the browser: http://prntscr.com/bzeu4l
And here's what happens behind the scenes: http://prntscr.com/bzets2
Normally it would be completely and utterly irrelevant to me since the content is displayed properly. But when I unhide the textarea, it's clear that it receives the exact same data, with whitespaces: http://prntscr.com/bzeum8
This is a big problem because I don't want the DB values to be overwritten with spaces.
I could work around this by using regex and stripping what has more than 2 spaces when I save the data. But this feels like a workaround, not a solution.
Does anyone know an elegant solution to this? Since I'm a Laravel newbie, it's very possible that I'm missing something obvious about displaying variable values in Blade.
Thanks in advance.
PS: If anybody has any suggestions about my approach / if my approach with the textarea is flawed, I warmly welcome criticism.
Also, I am terribly sorry for the vague layout of the page, it's still in a very incipient stage. In case it's not evident, 'testhomecontent' and 'testservices' are practically $page[0]->content and $page[1]->content.

In blade when all spaces between the contents are preserved. So, to get rid of spaces change your following code
<div hidden class="editable-page-edit-mode" id="{{ $page->page }}">
<textarea class="page-edit">
{{ $page->content }}
</textarea>
</div>
To this:
<textarea class="page-edit">{{ $page->content }}</textarea>

Change
<textarea class="page-edit">
{{ $page->content }}
</textarea>
To
<textarea class="page-edit">{{ $page->content }}</textarea>

Related

how to pass callback function in component? (laravel alpine.js)

I make a draft implementation for my reusable input component.
The code below obviously throws an error.
Question is how to pass the $event back to register blade to get or log the value of the input?
register.blade.php
<div>
<x-input onChange="(value) => {console.log('value', value)}"></x-input>
<div/>
input.blade.php
#props(['onChange' => 'null'])
<input x-on:change="{{ $onChange($event) }}">
A few things here.
First off, your markup is wrong. You have a the closing slash at the wrong end of the closing div. Should be </div> not <div/>.
Then you're using x-on without x-data. Alpine only picks up components with the x-data attribute.
Finally, events propagate automatically, so you could just listen on the parent instead:
{{-- register.blade.php --}}
<div x-data>
<x-input x-on:change="console.log('value', $event.target.value)" />
</div>
{{-- input.blade.php --}}
<input {{ $attributes }}>
I learned we could just achieve this through Alpine.Js dispatch. I don't need to pass onClick props via Laravel component. I just simply use dispatch to listen the event (x-on).
What I like in this implementation is that,
aside of event information, passing of extra data is easy
you don't have to use Laravel props and assigned unnecessary props in the tag.
register.blade.php
<div>
<x-input x-on:custom-input="console.log('your values =', $event.target.newValue)"
></x-input>
<div/>
input.blade.php
<input x-on:change="$dispatch('custom-input', { newValue: $event.target.value })">
you can pass "key" prop to distinguish each component.

Laravel Components: default content in {{ slots }}

In old-style Laravel blade templated we used to use #section('section-name') in the following way:
{{-- h1para.blade.php --}}
<h1>
#section('heading')
Heading from Template
#endsection
</h1>
<p>
#yield('details')
</p>
And then extend that template with:
{{-- content.blade.php --}}
#extends('h1para')
#section('details')
Content from content page
#endsection
In the above, my rendered HTML output would look like the following, because the "missing" 'heading' section in the extending file means that we default back to the content in the template:
<h1>Heading from Template</h1>
<p>Content from content page</p>
But in the new components way of doing things, I do:
{{-- .../components/h1para.blade.php --}}
<h1>{{ $heading }}</h1>
<p>{{ $slot }}</p>
In case you haven't gathered, the question is: how do I set a default value for a slot's contents, such that if it isn't supplied in the extending component/template, it falls back to that default?
(I've done my searches, but haven't been able to find the same question asked before)
EDIT:
I should add that I've seen the solution (in the Laravel documentation):
<h1>{{ $heading ?? 'Default Heading Here' }}</h1>
But this seems only to be appropriate if the default value is a short easy to manage string. If the default is a long stream of HTML, then it wouldn't work for my needs.
EDIT 2:
Just to reiterate: the whole point of the question is that the default content could be a long stream of HTML. Solving the problem by passing in a string (be that formatted as HTML or not) wouldn't work for my real-world needs.
I think the solution is this:
{{-- .../component/template.blade.php --}}
<div>
#if (isset($heading))
{{ $heading }}
#else
<h1>Default Heading<span class="subhead">default subheadin and lots of other html content</span></h1>
#endif
<p>{{ $slot }}</p>
</div>
It's not super elegant, but I think it's the only solution. Anyone else have a better answer, I'd love to hear it.
If you pass data like:
<x-h1para header="<span>Header content</span>">
<div>Default slot content here</div>
</x-h1para>
You can display in your component like:
<div>
<h1>{!! $heading ?? 'Default Heading Here' !!}</h1>
{{ $slot }}
</div>

How to display contenteditable contents properly? (laravel) (vue)

I have done saved the contents inside the #descrition below.
<div id="description" contenteditable="true"></div>
My problem is when I try to display it does not display like an html format, it displays same like the saved data with <h1></h1> & <br>. It displays plain text only.
<div id="description" contenteditable="true">{{ $description }}</div>
The content I saved in my database & display:
<h1>Descriptoin</h1> Doner, where I built and maintained banner adverts and microsites. <br> And...
Someone know how to display this properly?
Answer: thanks to #Akram Wahid
In laravel - {!! $description !!}
In vue - <div v-html="description"> </div>
You have to do like this , because Blade {{ }} statements are automatically sent through PHP's htmlspecialchars function to prevent XSS attacks.If you do not want your data to be escaped, you may use the following syntax:
<div id="description" contenteditable="true">{!! $description !!}</div>
By default Laravel escape special characters to prevent XSS attack.
Try using this format:
<div id="description" contenteditable="true">{!! $description !!}</div>

HTML output with spaces in laravel

I've never met this behaviour while working with laravel, but now I got something annoying. I have this code:
<span class="category-list">
(#foreach ($material->categories as $category)
{{ $category->name }}
#endforeach) )
</span>
And I got this output:
As you can see I got a lot of spaces here. I suppose that's because I have tabs in my code (tabs automatically converted to spaces in phpstorm). But how to deal with it except having ugly code without spaces?
I think I'm missing something simple as I've never had such trouble
Where is this data coming from? What happens when you dump this from your controller? (still extra whitespace?)
If the whitespace is indeed in the property itself and it serves a purpose, you could make a Macro to trim() it, or trim() it in-line.
trim():
<span class="category-list">
(#foreach ($material->categories as $category)
{{ trim($category->name) }}
#endforeach) )
</span>
Or Macro:
Macro: (register the macro)
Form::macro('trimWhitespace', function($val)
{
// do anything you want to $val.
return trim($val);
});
View: (use the macro)
<span class="category-list">
(#foreach ($material->categories as $category)
{{ Form::trimWhitespace($category->name) }}
#endforeach) )
</span>

Loading a codeigniter view with a form from inside another view

Using codeigniter, I've been trying to load a view inside of a foreach loop, as follows:
$posts = $this->postslibrary->getAllPosts();
foreach($posts as $post){
$home['content'][$i] = $this->load->view('post', $post['data'], true);
$i++;
}
$this->load->view('head');
$this->load->view('home', $home);
$this->load->view('footer');
Each of those post views looks a little like this:
<div class="postnum<?=$post_num?>">
<p>Posted by: <?=$poster_name?></p>
<p>Reply to: <?=$poster_name?></p>
<form>
<input type='text' />
<input type='submit' />
</form>
</div>
And they're being loaded mostly successfully in the 'home' view (which is below for thoroughness).
<div ="posts">
<?php
for($i=0;$i<$count;$i++)
{
echo($content[$i]);
}
?>
<div class="clear"></div>
<a href='/posts/browse/'>Load more items</a>
</div>
But my output ends up looking like:
<div class='posts'>
<div class='postnum1'>
<p>Posted By: Jim</p>
<p>Reply to Jim</p>
<input type='text' />
<input type='submit' />
</div>
</div>
Why are my form tags not coming through?
Check if you already have a form around the current form. Chrome is one of the browsers which doesn't accept this and removes the second form. Using a form in a form is bad practice and I suggest you find a different solution to do the form handling.
Slightly left-of-field answer, but have a look at CodeIgniter Form Generator. I've used it a couple of times and it seems pretty good for generating forms from an array. It's a bit tricky to get your head around it to begin with, but it works well once you've gotten into it.
The basic idea is that you implement a form controller from your ordinary controller, and then just output it in your view file. It might be a more elegant (and sustainable) solution to what you're trying.

Resources