0

Question- How do I point to my image inside the public folder from within a react class without using jsx?

FYI - The console shows the full 'string' path I give the img element with the appended filename with 'aData[6]'. For example, if I use "%PUBLIC_URL%" as shown below, it prints out that full string, unlike in the base html class where this is converted.

I know this isn't the best way to go about this, but I'm trying to re-use the existing code without re-writing it.

I have a react class that generates an 'expandable' table with an avatar image included. In order for the image to be properly loaded, the table has an 'init' method to write out all the proper tags, etc. I'm not sure how to go about telling react where the image is. In my base index.html class, I used '%PUBLIC_URL%' to point at the public folder, but here I'm inside an active react class so not sure about it. The images will be dynamic moving forward so importing them directly won't work even if I was using JSX to generate this table.

I'm trying to avoid re-writing this particular class and it's methods, just trying to port them over to my react project structure.

Here's the code:

import React, { Component } from 'react' 
import $ from 'jquery'
import datatables from 'datatables.net'
import { Link } from 'react-router-dom'

class EmployeeTablev2 extends Component {

constructor(props) {
    super(props)


    this.init = this.init.bind(this)
}

componentDidMount() {
    this.init()
}


init() {
        /* Formatting function for row details */
        function fnFormatDetails(oTable, nTr) {
            var aData = oTable.fnGetData(nTr);
            var sOut = '<table>';
            sOut += '<tr><td rowspan="5" style="padding:0 10px 0 0;"><img src="/assets/img/avatars/' + aData[6] + '"/></td><td>Name:</td><td>' + aData[1] + '</td></tr>'
            sOut += '<tr><td>Age: </td><td>' + aData[3] + '</td></tr>'
            sOut += '<tr><td>Address: </td><td>' + aData[2] + '</td></tr>'
            sOut += '<tr><td>Position: </td><td>' + aData[4] + '</td></tr>'
            sOut += '<tr><td>Others: </td><td><a href="">Something here</a></td></tr>'
            sOut += '</table>'
            return sOut
        }

        /*
         * Insert a 'details' column to the table
         */
        var nCloneTh = document.createElement('th');
        var nCloneTd = document.createElement('td');
        nCloneTd.innerHTML = '<i class="fa fa-plus-square-o row-details"></i>';

        $('#expandabledatatable thead tr').each(function() {
            this.insertBefore(nCloneTh, this.childNodes[0]);
        });

        $('#expandabledatatable tbody tr').each(function() {
            this.insertBefore(nCloneTd.cloneNode(true), this.childNodes[0]);
        });

        /*
         * Initialize DataTables, with no sorting on the 'details' column
         */
        var oTable = $('#expandabledatatable').dataTable({
            "sDom": "Tflt<'row DTTTFooter'<'col-sm-6'i><'col-sm-6'p>>",
            "aoColumnDefs": [
                { "bSortable": false, "aTargets": [0] },
                { "bVisible": false, "aTargets": [6] }
            ],
            "aaSorting": [[1, 'asc']],
            "aLengthMenu": [
                [5, 15, 20, -1],
                [5, 15, 20, "All"]
            ],
            "iDisplayLength": 5,
            "oTableTools": {
                "aButtons": [
                    "copy",
                    "print",
                    {
                        "sExtends": "collection",
                        "sButtonText": "Save <i class=\"fa fa-angle-down\"></i>",
                        "aButtons": ["csv", "xls", "pdf"]
                    }
                ],
                "sSwfPath": "assets/swf/copy_csv_xls_pdf.swf"
            },
            "language": {
                "search": "",
                "sLengthMenu": "_MENU_",
                "oPaginate": {
                    "sPrevious": "Prev",
                    "sNext": "Next"
                }
            }
        })


        $('#expandabledatatable').on('click', ' tbody td .row-details', function() {
            var nTr = $(this).parents('tr')[0];
            if (oTable.fnIsOpen(nTr)) {
                /* This row is already open - close it */
                $(this).addClass("fa-plus-square-o").removeClass("fa-minus-square-o");
                oTable.fnClose(nTr);
            } else {
                /* Open this row */
                $(this).addClass("fa-minus-square-o").removeClass("fa-plus-square-o");;
                oTable.fnOpen(nTr, fnFormatDetails(oTable, nTr), 'details');
            }
        })

        $('#expandabledatatable_column_toggler input[type="checkbox"]').change(function() {
            var iCol = parseInt($(this).attr("data-column"));
            var bVis = oTable.fnSettings().aoColumns[iCol].bVisible;
            oTable.fnSetColumnVis(iCol, (bVis ? false : true));
        })

        $('body').on('click', '.dropdown-menu.hold-on-click', function(e) {
            e.stopPropagation();
        })
    }


eachEmployee(employee, i) {
    return (
            <tr key={employee.id}>
                <td data-value={employee.id}>
                    {employee.name}
                </td>
                <td data-value={employee.id}>
                    {employee.address}
                </td>
                <td data-value={employee.id}>
                    {employee.age}
                </td>
                <td>
                    {employee.position}
                </td>
                <td>
                    <div>
                        <Link to={`/employee/${employee.id}`} className="btn btn-default">
                            View
                        </Link>
                    </div>
                </td>
                <td>
                    {employee.pic}
                </td>
            </tr>
    )
}

render() {
    return (
            <div className="row">
                <div className="col-xs-12 col-md-12">
                    <div className="widget">
                        <div className="widget-header ">
                            <span className="widget-caption">Expandable DataTable</span>
                            <div className="widget-buttons">
                                <a href="#" data-toggle="maximize">
                                    <i className="fa fa-expand"></i>
                                </a>
                                <a href="#" data-toggle="collapse">
                                    <i className="fa fa-minus"></i>
                                </a>
                                <a href="#" data-toggle="dispose">
                                    <i className="fa fa-times"></i>
                                </a>
                            </div>
                        </div>
                        <div className="widget-body">
                            <table className="table table-striped table-bordered table-hover" id="expandabledatatable">
                                <thead>
                                    <tr>
                                        <th>
                                            Name
                                        </th>
                                        <th>
                                            Address
                                        </th>
                                        <th>
                                            Age
                                        </th>
                                        <th>
                                            Position
                                        </th>
                                        <th>
                                            View
                                        </th>
                                        <th>Picture</th>
                                    </tr>
                                </thead>

                                <tbody>
                                    {this.props.employees.map(this.eachEmployee)}
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        )
}
}

export default EmployeeTablev2

So inside this init method, there's a method named 'fnFormatDetails, which pulls the data from the table and creates an inner table that will display it when the table row is 'expanded'. Included is a picture in the 6th position. Any help is appreciated, but as I stated, just trying to figure out how to load the image in this way without having to re-write to use jsx.

Thanks

SteveManC
  • 132
  • 4
  • 12
  • Please state the question with question mark and maybe in bold font. What do you see in console? how does this work now? – zmii Jun 26 '18 at 14:25
  • Possible duplicate of [Render HTML string as real HTML in a React component](https://stackoverflow.com/questions/39758136/render-html-string-as-real-html-in-a-react-component) – Lukas Bach Jun 26 '18 at 14:38
  • As stated above in my edit, the console shows it was unable to load the image. My first thought was to add "%PUBLIC_URL%" as I have done in my index.html class to properly import my css, however this doesn't work here, no surprise. I also tried to explicitly define the path as '../../public/assets... etc.' but had no luck either. The index.html after being rendered shows /assets/.... instead of the '%PUBLIC_URL%/assets' so I tried that as well, with the same results. – SteveManC Jun 26 '18 at 14:46

2 Answers2

0

Assuming that aData is just an array of td nodes, it looks like you are using the wrong index when querying the array. You are doing 6 instead of 5.

sOut += '<tr><td rowspan="5" style="padding:0 10px 0 0;"><img src="/assets/img/avatars/' + aData[5] + '"/></td><td>Name:</td><td>' + aData[1] + '</td></tr>'

  • I had thought that too, but when I inspect the element it is actually displaying the correct data. Not sure why index isn't starting with 0 here. I'm not too familiar with datatable, so may be something with it. Thanks though. – SteveManC Jun 26 '18 at 14:38
  • So when you inspect the image element, does the src path look right? If it does, then it is possible that the images are not located at PUBLIC_URL/assets/img/avatars/ – Kevin Valentine Jun 26 '18 at 14:46
  • I've only recently started in react so I can't say for sure about the paths, other than what I see in the explorer. I had typed the full path to my css in my index.html to begin and they didn't load, and I found that I needed to put '%PUBLIC_URL%' in order for them to be properly located. I tried this here but didn't think it would work since it was only being printed to the page and not rendered, which ended up being correct. – SteveManC Jun 26 '18 at 14:52
0

I was in the process of putting a build on our webserver to test a few things and accidentally answered my question. While this does not work in the development environment, after I create my build (I'm using create-react-app so I ran npm run build), The images are loading with explicit paths defined, i.e. '/assets/img/avatar/myimage.jpg' I appreciate the suggestions and help given, hopefully this might help someone else who comes across this while developing. Thanks

SteveManC
  • 132
  • 4
  • 12