Wesley Smith
Wesley Smith

Reputation: 19571

Fit dynamic elements on rows taking all available space without breaking groups across multiple lines

I have a dynamic form, in that my users can add categories, groups, and individual inputs to the form dynamically.

I need to be able to print the completed form and have it layout to look decent on a printed page.

The actual form can be quite complex so to keep it as simple as possible, Iv'e made a separate page for printing that displays very minimal content

Here is a jsFiddle of what I have so far enter image description here

My problem areas are marked in red and purple below

Purple: I'd like the last input-value field on each row to exted to the right to take up all remaining room on that row.

Red: I'd like to set the input-label and input-value to never break across multiple lines like this. If there is not enough room on the row for both, they should both be moved to the next row.

html,body{
    font-family: Arial, Helvetica, sans-serif;
}
.print-container {
    width: 210mm;
    /*height: 297mm;*/
    margin-left: auto;
    margin-right: auto;
    display: table;
    height:50px;
}

.vtop {
    vertical-align: top;
}

.print-header{
    color: #909090 !important;
    font-size: 26px !important;
    line-height: 26px !important;
    font-weight: bold !important;
    padding-bottom:24px !important;
    margin-top: 30px;
}

.print-header-text{
    transform:scale(1.1,1.3);  /* W3C */
    -webkit-transform:scale(1.1,1.3);/* Safari and Chrome */
    -moz-transform:scale(1.1,1.3);/* Firefox */
    -ms-transform:scale(1.1,1.3);/* IE 9 */
    -o-transform:scale(1.1,1.3);/* Opera */
    padding-top:22px;
}

.print-category-header{
    text-align:center !important;
    text-transform: uppercase !important;
    color: #606269 !important;
    background-color: #f2f2f2 !important;
    padding-top:5px;
    padding-bottom:5px;
}
legend{
    background-color: #ffffff;
    padding-right: 7px;
    padding-left: 7px;
    font-size: 16px;
    text-transform: uppercase;
    color: #606269 !important;
}
.print-category-header{
    margin-top:20px;
}
.left{
    float:left;
}
.print-header{
    width: 100%;
    height:auto;
}
.print-header>div{
}
.col-3{
    width:25%;
}
.col-6{
    width:50%;
}
.col-9{
    width:75%;
}
.col-12{
    width: 100%;
}
.row:after,.clearfix:after,fieldset:after {
    content: " ";
    display: block;
    height: 0;
    clear: both;
}
.row>div,.input-label,.input-value{
    float: left;
}
.input-value {
    margin-left: 10px;
    color:#999999;
    min-width: 118px;
    border-bottom: 1px solid #999999;
    height: auto;
    margin-top: 10px;
    display: inline-block;
    margin-right:15px;
}
.input-row{
    white-space: nowrap;
}
.input-label{
    height: auto;
    margin-top: 10px;
}
.text-center{
    text-align: center;
}
.category{
    width:100%;
}
fieldset {
    border: 1px solid #CCCCCC;
    margin-top:10px;
}
@media print and (color) {
    * {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}
<div class="print-container">

    <div class="print-header row">
        <div class="col-3 text-center "><img width="176.5" height="73.15019011406845" src="https://placeholdit.imgix.net/~text?txtsize=33&txt=176%C3%9773&w=176.5&h=73.15019011406845" alt=""></div>
        <div class="col-9 text-center vtop print-header-text">PREPLAN DATA COLLECTION</div>
    </div>
    <div id="saved-form-info" class="beginsHidden" data-saved-form-id="" data-inputs-to-remove=""></div>
    <div id="category-tab-container">
        <div class="category">
            <div class="print-category-header">First Category</div>
            <div class="input-group">
                <fieldset>
                    <legend><div class="group">Grup Name</div></legend>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">Some content</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">Some longer content</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">Small</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">Some even longer longer content</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                </fieldset>
            </div>
        </div>
        <div class="category">
            <div class="print-category-header">Second Category</div>
            <div class="input-group">
                <fieldset>
                    <legend><div class="group">Grup Name</div></legend>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                    <div class="input-row">
                        <div class="input-label">Input Label</div>
                        <div class="input-value">&nbsp;</div>
                    </div>
                </fieldset>
            </div>
        </div>
    </div>

</div>

How can I fix these two issues?

I am open to Javascript/jQuery solutions if necessary

Upvotes: 1

Views: 81

Answers (2)

Wesley Smith
Wesley Smith

Reputation: 19571

Here is a snippet of what I ended up with based off @Armina's answer which was good but behaved differently on different size screens.

Here is a jsFiddle

enter image description here

$.fn.extend({
    alignRows: function (options) {
        var defaults = {
            container: '#print-container', // the selector for the container element that holds all the groups
            label: '.input-label', // the selector for the elements holding the labels for the inputs
            value: '.input-value', // the selector for the elements holding the values for the inputs
            pair: '.input-pair', // the selector for the wrapper element that holds the label and value
            ignore: 'col-12' // a classname to ignore, these elements will not be evaluated or changed, style these some other way
        };
        options = $.extend(defaults, options);
        this.each(function (g, el) {
            var $group = $(el);
            var $pairs = $group.find(options.pair);
            $pairs.each(function (i, e) {
                var $this = $(e);
                var $label = $this.find(options.label);
                var $value = $this.find(options.value);
                var $nextPair = $pairs.eq(i + 1);
                if ($nextPair.length > 0) {
                    var thisTop = $this.offset().top;
                    var nextTop = $nextPair.offset().top;
                    if (thisTop != nextTop && !$this.hasClass(options.ignore)) {
                        //console.log('break to new row'); 
                        $this.stretch(options);
                    }
                } else {
                    //console.log('last in row'); 
                    $this.stretch(options);
                }
            });
        });
        return this;
    },
    stretch: function (options) {
        this.each(function (g, el) {
            var defaults = {};
            var $this = $(el);
            $this.css('margin-right', '0px').css('margin-right', '0px');
            var $value = $this.find(options.value);
            var elementWidth = $value.outerWidth(true);
            var elementLeft = $value.offset().left;
            var elementRightEdge = elementWidth + elementLeft;
            var containerWidth = $(options.container).outerWidth();
            var containerLeft = $(options.container).offset().left;
            var containerRightEdge = containerWidth + containerLeft;
            var offset = containerRightEdge - elementRightEdge;
            var newWidth = (elementWidth + offset) - 30;
            $value.css('width', newWidth + 'px');
            /*
            console.log('elementRightEdge  is ' + elementRightEdge);
            console.log('containerRightEdge  is ' + containerRightEdge);
            console.log('difference is ' + offset);
            console.log('stretching element to ' + newWidth);
            */
        });
        return this;
    }
});
$('.input-group').alignRows();
html, body {
    font-family: Arial, Helvetica, sans-serif;
}
#print-container {
    width: 210mm;
    /*height: 297mm;*/
    margin-left: auto;
    margin-right: auto;
    display: table;
    height:50px;
    position:relative;
}
.print-header {
    color: #909090 !important;
    font-size: 26px !important;
    line-height: 26px !important;
    font-weight: bold !important;
    padding-bottom:24px !important;
    margin-top: 30px;
}
.print-header-text {
    transform:scale(1.1, 1.3);
    /* W3C */
    -webkit-transform:scale(1.1, 1.3);
    /* Safari and Chrome */
    -moz-transform:scale(1.1, 1.3);
    /* Firefox */
    -ms-transform:scale(1.1, 1.3);
    /* IE 9 */
    -o-transform:scale(1.1, 1.3);
    /* Opera */
    padding-top:22px;
}
.print-category-header {
    text-align:center !important;
    text-transform: uppercase !important;
    color: #606269 !important;
    background-color: #f2f2f2 !important;
    padding-top:10px;
    padding-bottom:8px;
    margin-bottom:-12px;
}
fieldset {
    border: 1px solid #CCCCCC;
}
legend {
    padding-top:5px;
    padding-right: 7px;
    padding-left: 7px;
    font-size: 16px;
    text-transform: uppercase;
    color: #606269 !important;
    /*border-top-right-radius:50%;
    background-color: #ffffff;
    border-top-left-radius:50%;*/
}
.print-category-header {
    margin-top:20px;
}
.print-header {
    width: 100%;
    height:auto;
}
.print-header>div {
}
.col-3 {
    width:25%;
}
.col-6 {
    width:50%;
}
.col-9 {
    width:75%;
}
.col-12 {
    width: 100%;
}
.col-12 .input-value{
    text-align:left;
}
.row:after, .clearfix:after, fieldset:after {
    content:" ";
    display: block;
    height: 0;
    clear: both;
}
.row>div, .input-label, .input-value {
    float: left;
}
.input-value {
    margin-left: 10px;
    color:#999999;
    min-width: 118px;
    border-bottom: 1px solid #999999;
    height: auto;
    margin-top: 10px;
    display: inline-block;
    margin-right:15px;
    font-size:14px;
    text-align:center;
}
.input-label {
    height: auto;
    margin-top: 10px;
}
.input-group {
    width:100%
}
.input-pair {
    display:inline-block;
}
.text-center {
    text-align: center;
}
.category {
    width:100%;
}
.next-on-new-line {
    float:none;
}
.on-new-line {
    float:none;
    margin-left:0px;
    width:98%
}
.vtop {
    vertical-align: top;
}
@media print and (color) {
    * {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="print-container">
    <div class="print-header row">
        <div class="col-3 text-center ">
           <img width="176.5" height="73.15019011406845" src="https://placeholdit.imgix.net/~text?txtsize=33&txt=176%C3%9773&w=176.5&h=73.15019011406845" alt="">
        </div>
        <div class="col-9 text-center vtop print-header-text">SOME FORM TITLE HERE</div>
    </div>
    <div id="category-tab-container">
        <div class="category">
            <div class="print-category-header">Test Category</div>
            <div class="input-group">
                <fieldset class="m-t-15">
                    <legend>
                        <div class="group">test</div>
                    </legend>
                    <div class="input-pair">
                        <div class="input-label">Client</div>
                        <div class="form-input input-value">Some company name here</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Account Number</div>
                        <div class="form-input input-value">24554558954-54</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Date</div>
                        <div class="form-input input-value">12/22/1983</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Some Input</div>
                        <div class="form-input input-value">Min-118px </div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Text Input</div>
                        <div class="form-input input-value">Expanded to fit space that is left</div>
                    </div>
                    <div class="input-pair col-12">
                        <div class=" input-label next-on-new-line">Some Long Content</div>
                        <div class="form-input input-value on-new-line">This line is for much larger text that should always take up a full row, like the contents of a textarea. This line makes use of the option `ignore` to tell the plugin to ignore the element so you can sytle it as you see fit elsewhere </div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Selectbox</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Multiple Selectbox</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Number</div>
                        <div class="form-input input-value">12</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Date</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Image Upload</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">File Upload</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                </fieldset>
            </div>
        </div>
        <div class="category">
            <div class="print-category-header">Second Category</div>
            <div class="input-group">
                <fieldset class="m-t-15">
                    <legend>
                        <div class="group">Group One</div>
                    </legend>
                    <div class="input-pair">
                        <div class="input-label">Text 1</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                    <div class="input-pair">
                        <div class="input-label">Text 2</div>
                        <div class="form-input input-value">&nbsp;</div>
                    </div>
                </fieldset>
            </div>
        </div>
    </div>
</div>

Upvotes: 0

Aminadav Glickshtein
Aminadav Glickshtein

Reputation: 24600

I write a function that do 2 things:

  1. Search where the input-value and input-label not on the same row, and if so it move the input-value to new raw (clear:left)

  2. After moving to new raw, id make the last input-value in the previous raw, to expand (row width - input far from the left)

JSFiddle: http://jsfiddle.net/7tnkL9b0/5/

The Code:

$('.category').each(function(){
    $('.input-row').each(function(){
        this_input=$('.input-value',this).offset().top
        this_label=$('.input-label',this).offset().top
        console.log(this_input,this_label)
        if(this_input!=this_label){
            console.log('here')
            $('.input-label',this).css('clear','both')
            $('.input-value',$(this).prev()).width(
                $(this).width()-$('.input-value',$(this).prev()).offset().left
            )
        }

        if($(this).next().length==0){
            $('.input-value',this).width(
               $(this).width()-$('.input-value',this).offset().left
            )
        }
    })
})

Screenshot

Upvotes: 1

Related Questions