How to remove New Line Breaks from Knockout html binding? - javascript

So currently I have a foreach loop that pulls in a list of messages, like a message center, where it shows the date/computed short subject/computed short message/status. So when it pulls in the short message I have it displayed as HTML since it's a message from an HTML Editor. But when it displays it displays with all the spaces and whatever else is in the message until it hits 25 characters.
How would I either remove the newline breaks from the html message upon adding it to the foreach loop? Or if I switched it over to the knockout text binding, remove the html characters and replace with a space?
Knockout:
self.ShortSubject = ko.computed(function () {
if (self.Subject().length < 20) {
return self.Subject();
}
else {
return self.Subject().substring(0, 20) + '...';
}
});
self.ShortMessage = ko.computed(function () {
if (self.Message().length < 50) {
return self.Message();
}
else {
return self.Message().substring(0, 50) + '...';
}
});
HTML:
<table class="table table-hover table-striped table-bordered text-center">
<thead>
<tr class="bg-success">
<th width="15%" class="table-title" data-bind="click: sortMessageType" style="cursor: pointer">Message Type </th>
<th width="25%" class="table-title" data-bind="click: sortSubject" style="cursor: pointer">Subject </th>
<th width="40%" class="table-title" data-bind="click: sortMessage" style="cursor: pointer">Message </th>
<th width="20%" class="table-title" data-bind="click: function(data, event) { sortDateCreated( $data, event ) }" style="cursor: pointer">Date Created </th>
</tr>
</thead>
<tbody data-bind="foreach: VisibleTemplates">
<tr>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.MessageType"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.ShortSubject"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.ShortMessage"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.DateTime"></td>
</tr>
</tbody>
</table>

The problem with truncating HTML is that you might have unclosed tags in it which could destroy the formatting of your page. So you probably want to just extract the text, which this answer tells you how to do.
If you feel confident that your table cells won't break with the HTML you're going to get, you can set the displaystyle for everything inside a cell to inline.
.short-message * {
display: inline;
}
<div class="short-message"><h1>Hi there</h1>
<div>Some Text</div>
<table>
<tr>
<td>One</td>
</tr>
<tr>
<td>Two</td>
</tr>
</table></div>

Related

How can i get data-id value(id) store in Array using JavaScript?

how can i get id number(data-id) using JavaScript. I'm using sortable.min.js for drag & drop. i want to get the td ID(data-id) which is inside of #drop table and store it into a array(sort)?
table.html
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Story</th>
</tr>
</thead>
<tbody id="drop" class="sortables">
<tr>
<td data-id="67">67</td>
<td>this is test post for (news2)d</td>
</tr>
<tr>
<td data-id="59">59</td>
<td>how to use custom fonts in dja</td>
</tr>
<tr>
<td data-id="51">51</td>
<td>how can i merge two forms fiel</td>
</tr>
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Story</th>
</tr>
</thead>
<tbody id="drag" class="sortables">
</tbody>
</table>
script.js
new Sortable(drag, {
group: '.sortables',
animation: 150,
});
new Sortable(drop, {
group: '.sortables',
animation: 150,
onChange: function (e, tr) {
sort = [];
$("#drog").children().each(function () {
sort.push({ 'id': $(this).data('id') })
});
console.log(sort)
},
});
As pointed out, you have a Typo in your Selector:
$("#drog")
Should be:
$("#drop")
You can also consider the following.
new Sortable(drag, {
group: '.sortables',
animation: 150,
});
new Sortable(drop, {
group: '.sortables',
animation: 150,
onChange: function (e, tr) {
var sort = [];
$("#drop > tbody > tr").each(function (i, row) {
sort.push({ 'id': $("td:first", row).data('id') });
});
console.log(sort);
},
});
Your previous code was targeting the children of #drop, which are <TR> elements and do not have the Data attribute.
The new code targets the 1st <TD> element of each row. This element has the Data attribute.

Accordion Up Down Arrows

I am trying to add a downward arrow when the section is closed and an upper arrow when the section is open - at the right end of the head of each tab in the accordion.
Below is the HTML that I've used. It has for-each loops.
-- Javascript
$(function () {
$('tr.accordion').click(function () {
$(this).nextUntil('.accordion').slideToggle(20);
});
});
td.bg-light-blue{ background-color:rgb(233,242,253) }
.text-mid{ font-size:14px }
<div class="box-table" id="div_SummaryReport">
<table class="research table text-center" id="tblSummary" width="100%">
<thead style="position:relative;">
<tr style="position:relative;">
<th align="center" width="20%" style="position:relative;"> </th>
<th align="center" width="20%" style="position:relative;" data-toggle="tooltip" data-placement="top" title="Total Calls"> Total Calls</th>
<th align="center" width="20%" style="position:relative;" data-toggle="tooltip" data-placement="top" title="Contacted"> Contacted</th>
<th align="center" width="20%" style="position:relative;" data-toggle="tooltip" data-placement="top" title="#of saved calls"> Saved</th>
<th align="center" width="20%" style="position:relative;" data-toggle="tooltip" data-placement="top" title="Percent"> Percent %</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.GroupingData) {
<tr class="accordion">
<td class="bg-light-blue text-mid" colspan="5"><span class="text-blue">#item.Key</span></td>
<td class="bg-light-blue">downarrow</td>
</tr>
foreach (var data in item.Value) {
<tr class="hidden-row">
<td>#data.Name</td>
<td>#data.TotalCalls</td>
<td>#data.Contacted</td>
<td>#data.Saved</td>
<td>#data.Percentage</td>
</tr>
} }
</tbody>
</table>
</div>
The actual page looks close to this Fiddle:
https://jsfiddle.net/jmmanne/35nne25r/ This is sample html without loop
solution in fiddle. simplest method is using a class and a pseudoelement. you'll probably want to use font-awesome or an image for the arrows, but I just used v and > for example. https://jsfiddle.net/VeritoAnimus/avw0d9j1/1/
CSS Update
tr.accordion td:last-child:after { float: right; }
tr.accordion td:last-child:after{ content: 'v'; }
tr.accordion.collapsed td:last-child:after{ content: '>' }
JS Update
$(function () {
$('tr.accordion').click(function () {
var acdn = $(this);
$(this).nextUntil('.accordion').slideToggle({
duration: 20,
complete: function () {
/* if we were just doing one element, we could do a simpler complete function this will only change when the animation completes. since there's multiple rows, this would be called multiple times, so that's a pain. hence why I check the row for which way I was going. */
if($(this).is(':hidden') && !acdn.hasClass('collapsed'))
acdn.addClass('collapsed');
else if (!$(this).is(':hidden') && acdn.hasClass('collapsed'))
acdn.removeClass('collapsed');
}
});
// if you don't care about when it changes, you could just do this instead.
// $(this).toggleClass('collapsed');
});
});
just realized I did the arrows backwards per your request. I'm used to seeing > as closed and V as open. It's an easy enough switch though.
tr.accordion td:last-child:after{ content: '>'; }
tr.accordion.collapsed td:last-child:after{ content: 'v' }

Changing text into an input and then back again on deselection

I have a button, when i click it, i transform its sibling into an input containing the text that it once held.
This works fine.
However, upon deselection of the input, I require it to go back to being text again, but the issue is, the const variable is being overwritten somehow?
Anyway, here is my current HTML and JS:
$(function() {
$(document).on("click", "table.table-striped > tbody > tr > td > a.copy-btn", function(e) {
e.preventDefault();
const $this = $(this),
text = $this.parent().parent().find("td.link").text();
$this.parent().parent().find("td.link").html(`<input type="text" class="form-control" value="${text}">`);
$this.parent().parent().find("td.link input").select();
if ($this.parent().parent().find("td.link input").blur()) {
$this.parent().parent().find("td.link").html(text);
}
});
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped">
<thead>
<tr>
<th class="title">link name</th>
<th class="title">Platform</th>
<th class="title">Link</th>
</tr>
</thead>
<tbody>
<tr>
<th class="body-text" scope="row">1</th>
<td class="body-text">Mark</td>
<td class="body-text link">Otto</td>
<td class="body-text">Copy
</td>
<td class="body-text">More
</td>
</tr>
<tr>
<th class="body-text" scope="row">1</th>
<td class="body-text">Otto</td>
<td class="body-text link">Mark</td>
<td class="body-text">Copy
</td>
<td class="body-text">More
</td>
</tr>
</tbody>
</table>
The line $this.parent().parent().find("td.link input").blur() will always return true.
It fires the blur event, and returns the jQuery collection.
If you wanted to check if the element was focused, the easiest would be just
$this.parent().parent().find("td.link input").get(0) === document.activeElement
However, that's not really what you want, you want an event handler instead, and you can add that during the creation of the element like this (with cleaned up code and cached elements etc)
$(function() {
$(document).on("click", "table.table-striped > tbody > tr > td > a.copy-btn", function(e) {
e.preventDefault();
var $this = $(this),
parent = $this.parent().parent(),
link = parent.find("td.link"),
text = link.text(),
input = $('<input />', {
'class' : 'form-control',
value : text,
type : 'text',
on : {
blur : function() {
$(this).parent().html(text);
}
}
});
link.html(input);
input.select().focus();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped">
<thead>
<tr>
<th class="title">link name</th>
<th class="title">Platform</th>
<th class="title">Link</th>
</tr>
</thead>
<tbody>
<tr>
<th class="body-text" scope="row">1</th>
<td class="body-text">Mark</td>
<td class="body-text link">Otto</td>
<td class="body-text">Copy
</td>
<td class="body-text">More
</td>
</tr>
<tr>
<th class="body-text" scope="row">1</th>
<td class="body-text">Otto</td>
<td class="body-text link">Mark</td>
<td class="body-text">Copy
</td>
<td class="body-text">More
</td>
</tr>
</tbody>
</table>
Change
if ($this.parent().parent().find("td.link input").blur()) {
$this.parent().parent().find("td.link").html(text);
}
to
var $input = $this.parent().parent().find("td.link input");
$input.off("blur")
$input.on("blur", function () {
$this.parent().parent().find("td.link").html(text);
});
Is something like this what you had in mind?
$(function() {
$(document).on("click", "table.table-striped > tbody > tr > td > a.copy-btn", function(e) {
e.preventDefault();
const $this = $(this),
text = $this.parent().parent().find("td.link").text();
$this.parent().parent().find("td.link").html('<input type="text" class="form-control" value="' + $.trim(text) + '">');
$this.parent().parent().find("td.link input").select();
$($this).closest('tr').find('.form-control').on('blur', function () {
var xThis = this;
var finText = $(xThis).val();
$(xThis).closest('td').html(finText);
$(xThis).off('blur');
});
return false;
});
})();
See my jsfiddle example: https://jsfiddle.net/fictus/mmwc06gm/

How to remove HTML tags from Knockout Text binding?

So I have a foreach loop that displays your list of messages that contains the date sent/computed short message/computed short message/status. I tried binding the short message as an HTML data-bind, but that causes the issue of it bringing in the new line breaks since the message comes in from an HTML editor. So I thought maybe there is a way to use the text data-bind and just remove the HTML tags from it.
Anyone know of a way to do this?
HTML:
<table class="table table-hover table-striped table-bordered text-center">
<thead>
<tr class="bg-success">
<th width="15%" class="table-title" data-bind="click: sortMessageType" style="cursor: pointer">Message Type </th>
<th width="25%" class="table-title" data-bind="click: sortSubject" style="cursor: pointer">Subject </th>
<th width="40%" class="table-title" data-bind="click: sortMessage" style="cursor: pointer">Message </th>
<th width="20%" class="table-title" data-bind="click: function(data, event) { sortDateCreated( $data, event ) }" style="cursor: pointer">Date Created </th>
</tr>
</thead>
<tbody data-bind="foreach: VisibleTemplates">
<tr>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.MessageType"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.ShortSubject"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.ShortMessage"></td>
<td class="mailbox-subject" data-bind="click: function(data, event) { $parent.selectTemplate( $data, event ) }, text: $data.DateTime"></td>
</tr>
</tbody>
</table>
Knockout:
self.ShortSubject = ko.computed(function () {
if (self.Subject().length < 20) {
return self.Subject();
}
else {
return self.Subject().substring(0, 20) + '...';
}
});
self.ShortMessage = ko.computed(function () {
if (self.Message().length < 50) {
return self.Message();
}
else {
return self.Message().substring(0, 50) + '...';
}
});
Your real problem is removing the HTML from the input text. In knockout you can use computed observables, or custom bindings to process the entry and removing the tags before showing it.
The problem of removing tags can be solved in several ways. For example, you can use this solution: Strip HTML from Text JavaScript (for example putting your text in a hidden or detached div), which is explained in a different way here.

jQuery DataTables plugin with JSON data source taking multiple POST requests on global search

Friends,
I'm using jQuery DataTables plugin. I'm doing the Server Side Processing with JSON datasource to fill the DataTable as showing in the example
Here's my code
HTML
<Table class="projectGrid DataTable display" id="tblList" width="100%">
<thead>
<tr>
<th align="center">
Created
</th>
<th align="center">
Assigned
</th>
<th align="center">
Stage
</th>
<th align="center">
Priority
</th>
<th align="center">
Status
</th>
</tr>
</thead>
<tfoot>
<tr>
<th align="center">
Created
</th>
<th align="center">
Assigned
</th>
<th align="center">
Stage
</th>
<th align="center">
Priority
</th>
<th align="center">
Status
</th>
</tr>
</tfoot>
<tbody>
<asp:Repeater ID="reptList" runat="server">
<ItemTemplate>
<tr>
<td align="center">
<%#Eval("CreatedBy")%>
</td>
<td align="center">
<%#Eval("AssignedTo")%>
</td>
<td align="center">
<%#Eval("Stage")%>
</td>
<td align="center">
<%#Eval("Priority")%>
</td>
<td align="center">
<%#Eval("Status")%>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
JavaScript
<script type="text/javascript">
var data =
{
datatableConfig: {
"aaSorting": [],
"processing": true,
"serverSide": true,
"ajax": {
url: "~/IssueData.asmx/GetIssueList",
type: "POST"
},
"columns": [
{ "data": "0" },
{ "data": "1" },
{ "data": "2" },
{ "data": "3" },
{ "data": "4" }
]
}
}
$(data.datatable + ' tfoot th').each(function () {
var title = $(this).text();
if (!$(this).hasClass('hidden')) {
$(this).html('<input type="text" class="footerInput" style="width:' + ($(this).width() - 10) + 'px" placeholder="Filter ' + $.trim(title) + '" />');
}
});
// Apply Datatable
if ($(options.datatable).length) {
table = $(options.datatable).DataTable(options.datatableConfig);
}
// Apply the search
table.columns().every(function () {
var that = this;
$('input.footerInput', this.footer()).on('change', function () {
if (that.search() !== this.value) {
that.search(this.value).draw();
}
});
});
</script>
Everything is working fine, except Search. When I enter single letter in a Search, It raises 3-4 Ajax POST Requests. Any Idea why it processes more POST requets on single keypress event?
You can use below code to apply search so when user press 'enter' key ajax request is made to search :
// Apply the search
table.columns().every(function () {
var that = this;
$('input.footerInput', this.footer()).on('keyup', function (e) {
if (e.keyCode == 13 && $.trim(this.value) !== '') {
that.search(this.value).draw();
}
});
});

Categories