The character + is converted into “&#x2B” in base64 encoded data

I am passing following string from MVC component (c#) to razor view;

var Count = "99+";

When I try to access this in razor view, i get &@x2B appended to it;

console.log(@Model.Count);
///
///--output
99&#x2B

Razor does some encoding. To get ride of this problem, we need to use @Html.Raw.

console.log(@Html.Raw(Model.Count)
///
///--output
99+

or better, use it with backtick operator;

let count = `@Html.Raw(Model.Count)`;
console.log(count);
///
///--output
99+

enjoy!

The Intersection Observer API: Practical Examples

This article demonstrates using the Javascript Intersection Observer API, instead of measuring scroll position, to perform common visibility detection tasks.

The Problem

In Javascript, performing an action when an element becomes visible to a user has previously always required the following:

  1. Detecting the current scroll position. Setting an event listener to do this is easy enough, but the performance overhead can be costly. You will almost always want to write a throttling function to limit the amount of events fired when a user is scrolling. If you don’t know how to write this yourself, then you might reach for a library like Lodash, etc. which adds another dependency to your codebase.
  2. Getting the top offset. Select the element you want to observe in the DOM and get its top offset relative to the element (or viewport) you are detecting. This may seem straightforward until you factor in any lazy loaded or async loaded content. Once you finally have that number, don’t forget to recalculate it because that pesky banner image loaded in at the last second and skewed your original number.
  3. Unset and cleanup. Once you run your logic, you need to remember to remove the event listener. Sometimes you may have several.
  4. Beware of main thread work. The function you pass to the event listener will be running on the main thread, and will be running hundreds or possibly thousands of times until your condition is met, even with the throttling you hopefully put in place.
  5. Other use cases. Last but not least, there are scenarios where you may want to detect when an element is about to become visible, or after a user has scrolled past an element by a certain threshold. This would require more changes to the logic above.

The Solution

The Intersection Observer API is an excellent solution to this problem. It’s a fairly recent browser API that lets developers hand most of these tasks off to the browser, in a way that is more optimized.

For more info, click here

Old techniques are here;

https://demos.flesler.com/jquery/scrollTo/

Modifying Exported DataTables Data

Three ways (and one legacy way) to perform detailed customization of data being exported from DataTables to targets such as Excel, PDF, etc.

  • The first way gives you access to the contents of each DataTable cell being exported.
  • The second way gives you access to the relevant object for the export target.
  • The third way uses orthogonal data.

(The fourth way is included for legacy information only – but may still be useful in some situations.)

Format the Source Data Cells

This is useful for formatting the raw data of each cell in your datatable, or accessing additional HTML element and attribute data which may be in each cell’s node.

See the export data options. There are three sections which can be formatted – the data is:

format.header
format.body
format.footer

Example: Write contents of <input> fields in a DataTable to output Excel, to capture user-provided data:

$(document).ready(function() {

  $('#example').DataTable({
    dom: 'Bfrtip',

    buttons: [
      {
        extend: 'excel',
        exportOptions: {
          format: {
            body: function ( inner, rowidx, colidx, node ) {
              if ($(node).children("input").length > 0) {
                return $(node).children("input").first().val();
              } else {
                return inner;
              }
            }
          }
        }
      }
    ]

  });

});

Customize the Exported Data Object

This is useful for performing more advanced customizations of the output (e.g. the Excel file or PDF file), which can’t be performed any other way.

The object you get depends on the export target.

TargetNotes
CSVThe CSV data as a single string, including newlines, etc.
ExcelAn object containing the XML files in the ZIP file structure used by Excel. You need to understand that zip structure to manipulate its data.
PDFAn object containing the PDFMake document structure.
copyThe data to be copied, as a string.
printThe window object for the new window. As such the document body can be accessed using window.document.body and manipulated using jQuery and DOM methods.

See here for a full list of the different export targets.

Excel example to format the output with a thin black border on each cell:

$(document).ready(function() {

  $('#example').DataTable( {

    dom: 'Bfrtip',
    buttons: [
      {
        extend: 'excelHtml5',
        customize: function ( xlsx, btn, tbl ) {
          var sheet = xlsx.xl.worksheets['sheet1.xml'];
          $( 'row c', sheet ).attr( 's', '25' );
        }
      }
    ]

  } );

} );

PDF example to change the font (see full details here for how to build your own vfs_fonts.js file):

$(document).ready(function() {
  $('#example').DataTable({

    dom: 'Bfrtip',
    buttons: [{
      extend: 'pdf',
      customize: function ( doc ) {
        processDoc(doc);
      }
    }]
  });
});

function processDoc(doc) {
  //
  // https://pdfmake.github.io/docs/fonts/custom-fonts-client-side/
  //
  // Update pdfmake's global font list, using the fonts available in
  // the customized vfs_fonts.js file (do NOT remove the Roboto default):
  pdfMake.fonts = {
    Roboto: {
      normal: 'Roboto-Regular.ttf',
      bold: 'Roboto-Medium.ttf',
      italics: 'Roboto-Italic.ttf',
      bolditalics: 'Roboto-MediumItalic.ttf'
    },
    arial: {
      normal: 'arial.ttf',
      bold: 'arial.ttf',
      italics: 'arial.ttf',
      bolditalics: 'arial.ttf'
    }
  };
  // modify the PDF to use a different default font:
  doc.defaultStyle.font = "arial";
  var i = 1;
}

Use Orthogonal Data

DataTables can use the orthogonal option when expoting data:

What orthogonal data type to request when getting the data for a cell.

An example which strips the leading dollar sign from salary values:

Sample data:

<tr>
    <td>Tiger Nixon</td>
    <td>System Architect</td>
    <td>Edinburgh</td>
    <td>61</td>
    <td>2011/04/25</td>
    <td>$320,800</td>
</tr>

The code:

var table = $('#example').DataTable( {
dom: 'Brftip',
  columnDefs: [
    {
      targets: [5],
      render: function (data, type, row) {
        return type === 'export' ? data.substring(1) : data;
      }
    }
  ],
  buttons: [ {
    text: 'CSV',
    extend: 'csvHtml5',
    name: 'testExport',
    exportOptions: {
      orthogonal: 'export'
    }
  } ]
} );

You can use whatever label you like instead of 'export'.

The end result is CSV data as follows:

"Tiger Nixon","System Architect","Edinburgh","61","2011/04/25","320,800"

Customize the Exported Data Arrays

Another export data option, similar to the above example, but this one provides the data after all of it has been gathered and pre-processed by all other formatting options:

customizeData

This is described in a DataTables forum comment as follows:

The customizeData option is a bit of a legacy hack. It was put in place before the Excel export buttons had a customize callback and it was the only way to modify the output data.

Data is provided in arrays:

header (array)
body (2-dimensional array)
footer (array)

No example given, as this is probably less useful compared to the other approaches shown above.

Showing and Hiding Long Data in a DataTable

The JavaScript:

var truncatedLength = 38; // set this to whatever you prefer

var table;
var origDataMap = new Map(); // the original (full) data for long text

$(document).ready(function() {

  table = $('#TableName').DataTable({
    columnDefs: [{
      targets: ['_all'],
      render: function(data, type, row, meta) {
        // sets up initially minimized text for content longer than truncatedLength:
        var api = new $.fn.dataTable.Api(meta.settings);
        var node = api.cell(meta.row, meta.col, {
          order: 'index'
        }).node();
        var hasToggler = $(node).children().length > 0;

        if (type === 'display' && !hasToggler && data.length > truncatedLength + 5) {
          origDataMap.set(meta.row + '-' + meta.col, data);
          var displayData = '<span>' + data.substr(0, truncatedLength) + '... </span>' +
            '<button class="moreless-button" data-state="trunc"' +
            ' onclick="showMoreOrLess(this, ' + meta.row + ', ' + meta.col + ')">more</button>';
          return displayData;
        } else {
          return data;
        }
      }
    }]
  });

});

//
// toggles the DOM table cell's contents (but it
// does not change the underlying DataTables data):
//
function showMoreOrLess(node, rowId, colId) {
  var displayData;
  var state = $(node).attr('data-state');
  var origData = origDataMap.get(rowId + '-' + colId);
  var cellNode = $(node).parent();
  if (state === 'trunc') {
    displayData = '<span>' + origData + ' </span>' +
      '<button class="moreless-button" data-state="full"' +
      ' onclick="showMoreOrLess(this, ' + rowId + ', ' + colId + ')">less</button>';
  } else {
    displayData = '<span>' + origData.substr(0, truncatedLength) + '... </span>' +
      '<button class="moreless-button" data-state="trunc"' +
      ' onclick="showMoreOrLess(this, ' + rowId + ', ' + colId + ')">more</button>';
  }
  cellNode.html(displayData);
}

The CSS:

/* makes a button look like a link */

.moreless-button {
  background: none!important;
  border: none;
  padding: 0!important;
  font-family: arial, sans-serif;
  color: #069;
  text-decoration: underline;
  cursor: pointer;
}

The HTML:

<!doctype html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Demo</title>

  <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script type="text/javascript" src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" />

  <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">

  <script type="text/javascript" src="https://cdn.datatables.net/plug-ins/1.10.24/dataRender/ellipsis.js"></script>



</head>

<body>

  <div style="margin: 20px;">

    <table id="TableName" class="display dataTable cell-border" style="width:100%">
      <thead>
        <tr>
          <th>Number</th>
          <th>Severity</th>
          <th>Description</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Number123</td>
          <td>S1</td>
          <td>Description size keeps on varying</td>
        </tr>
        <tr>
          <td>Number345</td>
          <td>S9 major alarm severe major alarm severe major alarm severe</td>
          <td>Unable to log on</td>
        </tr>
        <tr>
          <td>Number234</td>
          <td>S1</td>
          <td>Flashing red lights in the corner of my eyes</td>
        </tr>
        <tr>
          <td>Number765</td>
          <td>S3</td>
          <td>Description again is very very very long very very very long very very very long</td>
        </tr>
        <tr>
          <td>Number678</td>
          <td>S1</td>
          <td>Description size keeps on varying</td>
        </tr>
        <tr>
          <td>Number543</td>
          <td>S3</td>
          <td>Lorem ipsum dolor sit amet, consectetur "adipiscing" elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
            irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</td>
        </tr>
      </tbody>
    </table>

  </div>


</body>

</html>

Reference

https://stackoverflow.com/questions/67406187/how-to-truncate-a-field-data-in-datatable-and-add-more-options-towards-the-end/74006396#74006396