Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mPDF - Page break based on element height

I'm using mpdf in Laravel and with this package version 4.0

The problem is that I have a list of questions in different heights which have 4 options, and I don't know the exact and approximate height of every div tag which question and answer options are there, I don't want some part of my question to go to another page

All parts of my question have to be on one page and if this couldn't happen, mpdf put that question tag element on the next page (all parts of questions)

this picture is for now which is wrong:

sample question lists

what I want:

This image

so for this problem, I want to know the height of my question element so I can determine if the new page is needed to add a page break(same as this question on StackOverflow), or any other solution to fix my issue

this is my blade file:

@php
    error_reporting(0);
@endphp

    <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>سوالات</title>

    <style>
        html, body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'fa', sans-serif;
            direction: rtl;
        }

        .main-container{
            padding:20mm;
        }

        @page {
            footer: pagefooter;
            margin-top: 0pt;
        }

        @page:first {
            header: firstheader;
            margin-bottom: 200pt;
        }

        .item-answer{
            display: inline !important;
            width: 100%;
        }

        .sub-item-answer{
            float: left;
            display: inline !important;
            margin-top: 0 !important;
            padding-top: 0 !important;
            height: auto !important;
            margin-bottom: auto !important;
        }

        .sub-item-answer-num{
            width: 5%;
            float:right;
        }

        .q_1{
            margin-top: 45px !important;
        }

        .question{
            display: inline-block;
            page-break-inside: avoid !important;
            position: relative;
            float:right;
        }

        .question-row{
            display: inline !important;
            width: 100%;
        }

        .question-number{
            padding: 5px;
            background: #bebe27;
            border-radius: 10px;
            width:10% !important;
            text-align: center;
            color:#ffffff;
            font-weight: bold;
        }

        .main-question{
            width: 95% !important;
        }

        .row {
            margin-left: -15mm;
            margin-right: -15mm;
        }
    </style>
</head>
<body>
@php
    $i = 0;

@endphp

<htmlpageheader name="pageheader" style="display:none"></htmlpageheader>

<htmlpageheader name="firstheader">
    <img style="width: 100%;height:fit-content" src="http://api.amoozeshmelli.com/images/pdf/header.png" alt="header">
</htmlpageheader>

<sethtmlpageheader name="firstheader" value="on" show-this-page="1"/>

<sethtmlpageheader name="pageheader" value="on"/>

<div class="main-container container-fluid">

    @foreach($data as $question)
        @php
            $i++;
            $j=0;
        @endphp

        <div style="page-break-inside: avoid !important;" class="question q_{{$i}}">

            <div class="row question-row">

                <div class="question-number col-sm-1"> سوال{{$i}} </div>

                <div class="main-question col-sm-11">
                    @if($question->title)

                        {!! $question->title !!}

                        @if($question->image_url)
                            <img class="img-responsive" src="{{$question->image_url}}" alt="test">
                        @endif
                    @else
                        @if($question->image_url)
                            <img class="img-responsive" src="{{$question->image_url}}" alt="test">
                        @endif
                    @endif
                </div>

            </div>

            @if($question->options)
                <div class="question-main-container" style="float: right">
                    @foreach($question->options as $option)
                        @php
                            $j++;
                        @endphp
                        <div class="item-answer center-block row">
                            <div class="sub-item-answer-num col-sm-1">{{$j}})</div>
                            @if($option->title)
                                <div class="sub-item-answer col-sm-11">
                                    {!! $option->title !!}
                                    @if($option->image_url)
                                        <img style="width: auto; height:80px;" src="{{$option->image_url}}" alt="test" />
                                    @endif
                                </div>
                            @else
                                @if($option->image_url)
                                    <div class="sub-item-answer col-sm-11">
                                        <img style="width: auto; height:80px;" src="{{$option->image_url}}" alt="test" />
                                    </div>
                                @endif
                            @endif
                        </div>
                    @endforeach
                </div>

            @endif
            <hr>
        </div>
    @endforeach


</div>



<htmlpagefooter name="pagefooter">
    <p style="text-align: center;direction: rtl;">
        صفحه {PAGENO}
    </p>

    <img src="http://api.amoozeshmelli.com/images/pdf/footer.png" alt="header" style="z-index: 0 !important;width: 100%;">
</htmlpagefooter>

</body>
</html>

and I tried all methods in the documentation of mpdf and this answer but results were not useful

if any other solution exists please guide me

like image 225
Ali Avatar asked Jan 25 '23 07:01

Ali


1 Answers

After lots of tries, the issue solved!

the page-break-inside: avoid; doesn't work when I have a loop of block elements

I used a table for every question and put it in the main table and in it's <td> tag, the inner table now has autosize="1" which was needed

also, add this config to mPdf

$pdf->shrink_tables_to_fit = 1;

I added page-break-inside: avoid to the main table and the <tr> of questions in the loop

note that if you faced undefined index error try to solve it generally! but if like me, it doesn't fixed use error_reporting(0);

the corrected blade file:

@php
    error_reporting(0);
@endphp

    <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>سوالات</title>

    <style>
        html, body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'fa', sans-serif;
            direction: rtl;
        }

        .main-container{
            padding:40mm 20mm 40mm 20mm;
        }

        @page {
            footer: pagefooter;
            margin-top: 0pt;
        }

        @page:first {
            header: firstheader;
            margin-bottom: 200pt;
        }

        .item-answer{
            display: inline !important;
            width: 100%;
        }

        p{
            font-size:35px;
        }

        .sub-item-answer{
            margin-top: 0 !important;
            padding-top: 0 !important;
            height: auto !important;
            margin-bottom: auto !important;
        }

        .sub-item-answer > img{
            width: 100% !important;
            min-height: 200px;
            max-height: 500px;
        }

        .sub-item-answer-num{
            width: 5%;
            font-size: 35px;
        }

        .q_1{
            margin-top: 45px !important;
        }

        .question-number{

            padding: 20px !important;
            background: #bebe27;
            border-radius: 10px !important;
            width:auto !important;
            text-align: center;
            color:#ffffff;
            font-weight: bold;
            height: auto;
            font-size: 35px;
        }


        .main-question{
            width: 95% !important;
            font-size:30px;
        }
        
        .main-question > p{
            font-size:30px !important;
        }

        .main-question > img{
            width: 100% !important;
            min-width: 800px !important;
            max-width: 1000px !important;
            min-height: 200px;
            max-height: 500px;
        }

        .row {
            margin-left: -15mm;
            margin-right: -15mm;
        }
    </style>
</head>
<body>

@php
    $i = 0;
@endphp

<htmlpageheader name="pageheader" style="display:none"></htmlpageheader>

<htmlpageheader name="firstheader">
    <img style="width: 100%;height:fit-content" src="http://api.amoozeshmelli.com/images/pdf/header.png" alt="header">
</htmlpageheader>

<sethtmlpageheader name="firstheader" value="on" show-this-page="1"/>

<sethtmlpageheader name="pageheader" value="on"/>

<div class="main-container container-fluid">
    <table style="page-break-inside: avoid !important;">
        @foreach($data as $question)
            @php
                $i++;
                $j=0;
            @endphp
        <tr style="page-break-inside: avoid !important; min-height: 300px;">
            <td>
            <table autosize="1">
                <tbody>
              <tr>
              <td><span  class="question-number"> سوال{{$i}} </span></td>
              <td class="main-question col-sm-11">
                            @if($question->title)

                                {!! $question->title !!}

                                @if($question->image_url)
                                    <img class="img-responsive" src="{{$question->image_url}}" alt="test">
                                @endif
                            @else
                                @if($question->image_url)
                                    <img class="img-responsive" src="{{$question->image_url}}" alt="test">
                                @endif
                            @endif
                        </td>
        </tr>

                    @if($question->options)

                            @foreach($question->options as $option)
                                <tr>
                                @php
                                    $j++;
                                @endphp
                                    <td class="sub-item-answer-num col-sm-1">{{$j}})</td>
                                    @if($option->title)
                                        <td class="sub-item-answer col-sm-11" style="font-size:35px !important;">
                                            {!! $option->title !!}
                                            @if($option->image_url)
                                                <img style="width: 100% !important;min-height: 200px;max-height: 500px;" src="{{$option->image_url}}" alt="test" />
                                            @endif
                                        </td>
                                    @else
                                        @if($option->image_url)
                                            <td class="sub-item-answer col-sm-11">
                                                <img style="width: 100% !important;min-height: 200px;max-height: 500px;" src="{{$option->image_url}}" alt="test" />
                                            </td>
                                        @endif
                                    @endif
                                </tr>
                            @endforeach
                    @endif
                </tbody>
            </table>
            </td>
        </tr>
        @endforeach
        
    </table>
</div>



<htmlpagefooter name="pagefooter">

    <p style="text-align: left;direction: rtl; font-size: 15px; margin-top: 50px; padding-left:100px">
        صفحه {PAGENO}
    </p>
    <img src="http://api.amoozeshmelli.com/images/pdf/footer.png" alt="header" style="width: 100%;">

</htmlpagefooter>

</body>
</html>
like image 134
Ali Avatar answered Jan 26 '23 22:01

Ali