I am trying to use select2 as a tag entry. The values are there when it loads but when a value is added the current values get cleared.
var $serverType = $("#id_server_type");
current_values = ['Oracle DB'].map( function(item) {
$serverType.append('<option selected value="' + item + '">' + item + '</option>');
});
$.getJSON("/api/server-types/", function(data){
$serverType.html('');
$.each(data, function(key, val){
$.each(val, function(index, value) {
$serverType.append('<option value="' + value + '">' + value + '</option>');
})
});
});
$serverType.select2({
tags: true,
minimumInputLength: 0
});
I do not know enough about Javascript. Once you read the docs things become easier.
I was declaring the selected value(s) and then append to the list. Once I merged the logic it worked.
Related
The question is simple: How can i remove the date from line tooltip in the graph?
Use the tooltip formatter (documenation)
tooltip: {
formatter: function () {
return 'The value for <b>' + this.x +
'</b> is <b>' + this.y + '</b>';
}
},
You can also set the tooltip.headFormat to the empty string '' which disables the tooltip header (which displays the data).
API: https://api.highcharts.com/highcharts/tooltip.headerFormat
I am trying to append rows to a table using an array called searchResults. Everything works as expected until I introduce the jQuery UI dialog box. The problem is I need a new dialog box for each row in the first column. I'm pretty new to all of this so I'm pretty sure I'm using the index incorrectly at times. This is just to give you an idea of what I'm trying to accomplish. Any ideas how to do this correctly?
for (var i = 0; i < searchResults.length; i++)
{
$('#patientFileDialog[i]').dialog();
$'#openPFDialog[i]').click(function() {
$('#patientFileDialog[i]').dialog('open');
});
var dialog[i] = $(`<div id="patientFileDialog[i]" title="Patient File">${searchResults[i].patientWebLink}</div>`);
body.append('<tr>'+
`<td><button id="openPFDialog[i]">Click Here</button></td>` +
`<td>${searchResults[i].patientFirstName}</td>` +
`<td>${searchResults[i].patientLastName}</td>` +
`<td>${searchResults[i].patientDateOfBirth}</td>` +
`<td>${searchResults[i].patientDataPulseID}</td>` +
`<td>${searchResults[i].patientLaserFicheID}</td>` +
'</tr>')
}
After looking at your code a bit more I think I can see what you are trying to do. Working JSFiddle, with some faked searchResults so we can see it in action.
There are a few problems with the code in your question:
Using selectors like $('#patientFileDialog[i]') and $'#openPFDialog[i]') will try to match elements on the page with those IDs. AFAICT those don't actually exist yet, you are trying to create them.
var dialog[i] = ... sets up some divs as strings, but those are never added to the page;
As I mentioned in my comment, there are some syntax errors, maybe just typos and mixed up formatting here on SO;
Here's an updated version of the code. Notable changes:
Instead of adding an event handler for every individual openPFDialog button, it is better practice to add just one which matches them all. That single handler can then work out which button was clicked, and take the right action for just that one, not all of them. In this case if you have all your buttons use IDs that match openPFDialog-X, where X is a number, you can target anything matching that pattern (using a starts with selector, and find the X by removing the openPFDialog- part with replace.
There's an added complication with the above though. Selectors parsed at page load will only match elements that exist at that time. In this case, you're adding new elements to the page, and a selector defined at page load won't match them. The solution is to select instead some parent element which does exist at page load, and filter. This is called event delegation (search for the paragraph starting with "Delegated event handlers").
Working from what you have, I am guessing the patientFileDialogs you create should be placed inside some parent element which is not displayed on the page? That's what I've done.
Here's the code (and working JSFiddle):
var dialog, i;
// Single click handler for anything that starts with "openPFDialog-".
// Since those elements don't exist on the page yet, we need to instead
// select a parent object, say the body, and filter for clicks on our
// elements starting with our pattern
$('body').on('click', '[id^=openPFDialog]', function() {
// We need to find the "i"
i = $(this).attr('id').replace(/openPFDialog-/,'');
console.log('clicked on id', i);
$('#patientFileDialog-' + i).dialog();
});
for (var i = 0; i < searchResults.length; i++) {
// Create a new div with ID like "patientFileDialog-1", using the current
// search result
dialog = $('<div id="patientFileDialog-' + i + '" title="Patient File">' + searchResults[i].patientWebLink + '</div>');
// Add it to the page. I've use a div with ID dialogs which is hidden
$('#dialogs').append(dialog);
$('table').append('<tr>'+
'<td><button id="openPFDialog-' + i + '">Click Here</button></td>' +
'<td>' + searchResults[i].patientFirstName + '</td>' +
'<td>' + searchResults[i].patientLastName + '</td>' +
'<td>' + searchResults[i].patientDateOfBirth + '</td>' +
'<td>' + searchResults[i].patientDataPulseID + '</td>' +
'<td>' + searchResults[i].patientLaserFicheID + '</td>' +
'</tr>');
}
Update
One last suggestion - manipulating the DOM by adding/removing elements is slow. If you need to do that for each element in an array, it is best to avoid actually adding your content on each iteration, and rather just build up a string. Then once you're done iterating, just add the big single string, so you're chaning the DOM just once. Here's the basic changes needed to do that:
// Add some new variables to hold our big strings
var dialog, dialogs, row, rows, i;
// ... your code ...
for (var i = 0; i < searchResults.length; i++) {
// Create the dialog ...
dialog = ...
// Append it to our big string of all dialogs
dialogs += dialog;
// Same approach for rows
row = '<tr>'+ ... all that stuff
rows += row;
}
// Finished iterating, nothing added to DOM yet. Do it all at once::
$('#dialogs').append(dialogs);
$('table').append(rows);
Here is what I finally ended up having to do:
$(document).ready(function(){
if ($('[attr="searchResultsJson"]').length)
{
$('.approval-outer-wrap').prepend(drawTable());
$('.approval-outer-wrap').append('<div id="result-details" title="Search Result Detail"><p></p></div>')
}
$('body').on('click', '[id^=openPFDialog]', function() {
var result = $(this).parents('tr').data('result');
$('#result-details p').html(result.patientFirstName);
$('#result-details').dialog();
});
});
function drawTable(){
var table = $('<table id="search-results" />');
var header = $('<thead />');
table.append(header);
header.append('<tr><th>Patient File</th><th>First Name</th><th>Last Name</th><th>Date of Birth</th><th>Data Pulse ID</th><th>Laserfiche ID</th></tr>');
var body = $('<tbody />');
table.append(body);
var json = $('[attr="searchResultsJson"] [type="text"]').text();
var searchResults = JSON.parse(json);
for (var i = 0; i < searchResults.length; i++) {
body.append(`<tr data-result='${JSON.stringify(searchResults[i])}'>`+
`<td><button id="openPFDialog-` + i + `">🔍</button></td>` +
`<td>${searchResults[i].patientFirstName}</td>` +
`<td>${searchResults[i].patientLastName}</td>` +
`<td>${searchResults[i].patientDateOfBirth}</td>` +
`<td>${searchResults[i].patientDataPulseID}</td>` +
`<td>${searchResults[i].patientLaserFicheID}</td>` +
'</tr>');
}
return table;
}
Consider the following code.
function showPatientDialog(cnt){
$("#patient-file-dialog").html(cnt).dialog("open");
}
var d = $("<div>", {
id: "patient-file-dialog",
title: "Patient File"
})
.appendTo("body")
.dialog({
autoOpen: false
});
$.each(searchResults, function(i, result) {
var row = $("<tr>").appendTo(body);
$("<td>").appendTo(row).html($("<button>", {
id: "open-pdf-dialog-" + i
}).click(function() {
showPatientDialog(result.patientWebLink);
}));
$("<td>").appendTo(row).html(result.patientFirstName);
$("<td>").appendTo(row).html(result.patientLastName);
$("<td>").appendTo(row).html(result.patientDateOfBirth);
$("<td>").appendTo(row).html(result.patientDataPulseID);
$("<td>").appendTo(row).html(result.patientLaserFicheID);
});
I've got the code for Highcharts in combination with Thingspeak from here:
https://forum.arduino.cc/index.php?topic=213058.0
My problem is, I am not able to implement the different suffix into the code :-(. I've tried a lot, but I dont understand the mechanism behind the Java code.
I've tried some things, but result is, I only have one datafield for the first series but not for the other series...
Formatter function is on line 246.
My different yAxies on line 286.
How can formatter decide which yAxies do actual series use?
Maybe somebody have fun to help me?
http://jsfiddle.net/cbmj8rku/
Best regards, David
Each series is assigned to one yAxis. You can detect which series uses which axis for example by axis title:
tooltip: {
formatter: function() {
var points = this.points,
title,
result = '';
Highcharts.each(points, function(p) {
result += p.y;
title = p.series.yAxis.axisTitle.textStr;
if (title === 'yAxis1') {
result += 'suffix1<br>'
} else if (title === 'yAxis1') {
result += 'suffix2<br>'
} else {
result += 'suffix2<br>'
}
});
return result
}
}
Live demo: http://jsfiddle.net/BlackLabel/ncvtxoke/
I changed the code like this:
http://jsfiddle.net/cbmj8rku/20/
formatter: function() {
var d = new Date(this.x + (myOffset*60000));
var _Min = (d.getMinutes()<10) ? '0' + d.getMinutes() : d.getMinutes();
var _Sec = (d.getSeconds()<10) ? '0' + d.getSeconds() : d.getSeconds();
var s = d.getHours() + ':' + _Min + ':' + _Sec + '<br/>';
$.each(this.points, function () {
s += '<br/>' + this.series.name + ' <b>' + this.y + this.series.yAxis.userOptions.labels.suffix + '</b>';this.series.tooltipOptions.valueSuffix[this.point.index];
});
return s;
}
So in a current app, I have to use a custom Formatter on a couple rows in my jqGrid. All these do is take a few fields from my ajax call, concat them into one, and place that into a row.
EG ( data.toStreet + data.toCity + data.toState + data.toZip ) comes back as "Street City, State Zip" into the "To Address" column. This works fine and the data displays correctly, but when using the filtering toolbar, the filter is only based on the first val (data.street). below is a super simplified version of the pieces of code in question.
$('#grid').jqGrid({
...
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name:"toStreet" formatter: ToAddressFormatter},
{name:"fromStreet" formatter: FromAddressFormatter}
],
...
}),
$('#grid').jqGrid('filterToolbar',
{
stringResult:true,
searchOnenter: true,
defaultSearch: 'cn'
}
});
ToAddressFormatter = function(el, opt, rowObj){
var address = rowObj.toStreet+ " " + rowObj.toCity + ", " + rowObj.toState + " " + rowObj.toZip;
return address;
},
FromAddressFormatter = function(el, opt, rowObj){
var address = rowObj.fromStreet+ " " + rowObj.fromCity + ", " + rowObj.fromState + " " + rowObj.fromZip;
return address;
}
So if the value in the cel says "123 fake st, springfield, Va 22344" after being formatted, the filter toolbar can only search on "123 fake st" and nothing else.
Does anybody have any clue on how to remedy this, or possibly why it's happening and a good workaround??
EDIT:
I have included the beginning of my grid. Also, the property Address of result.d is created in the code below, and not returned from the webservice. My column is mapped to "Address" which displays the formatting properly, but still does not search as intended.
$('#grdDisasters').jqGrid({
datatype: function(postdata) {
var obj = { "showActive": $('#btnFilterActive.pressed').length > 0 ? true : false, "showInactive": $('#btnFilterActive.pressed').length > 0 ? true : false,
'page': postdata.page, 'rows': postdata.rows, 'sortIndex': postdata.sidx, 'sortDirection': postdata.sord, 'search': postdata._search,
'filters': postdata.filters || ''
};
$.ajax({
url: "/GetGrid",
data: JSON.stringify(obj),
success: function(result) {
for (var i = 0, il = result.d.rows.length; i < il; i++) {
LoadedDisasters[i] = result.d.rows[i];
result.d.rows[i].cells.Address = result.d.rows[i].cells.Street + " " + result.d.rows[i].cells.City + ", "+ result.d.rows[i].cells.State+ " "+ result.d.rows[i].cells.Zip;
}
result.d = NET.format(result.d);//just correctly format dates
UpdateJQGridData($('#grdDisasters'), result.d);
},
error: function(result) {
//alert("Test failed");
}
});
jqGrid has a problem filtering rows when data is formatted using custom/predefined formatter.
You will have to filter rows on the server-side.
Add 2 more request parameter in your controller to handle jqgrid search request:
When jqGrid requests for filtered raws it will add a parameter: _search with value: true
and all the search parameter like col1=abc&col4=123 meaning user wanted to filter using column named col1 and column named col4 with values respectively: abc and 123
Use those values and query the database with like operation something as follows:
select id, concat(street1, street2, city, state, zip) as address
where address like "%abc%" and id like "%123%"
return these rows as json to jqGrid and display those in the current page. So basically you will have to have a jqGrid with server-side paging, sorting and searching. You can not use client-side paging, sorting and searching features. Also, make sure you don't have loadonce: true set.
I think that you fill the grid in the wrong way. If your source data has toStreet, toCity, toState, toZip, fromStreet, fromCity, fromState, fromZip properties and you need to have composed addressTo and addressFrom you should do this in another way. Your problem is that toStreet and fromStreet will be saved locally in the internal data parameter in the original format like you get it from the server. The local searching uses the data parameter, so the toStreet and fromStreet like you get there from the server will be used.
You don't posted more full code of jqGrid which you use. So I suppose that you use datatype: 'json', datatype: 'jsonp' or datatype: 'xml' in combination with loadonce: true. You should define colModel
$('#grid').jqGrid({
...
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name: "addressTo", ...},
{name: "addressFrom", ...}
],
beforeProcessing: function (data) {
var i, rows = data.rows, l = rows.length, item;
for (i = 0; i < l; i++) {
item = rows[i];
item.addressTo = item.toStreet + " " + item.toCity + ", " +
item.toState + " " + item.toZip;
item.addressFrom = item.fromStreet+ " " + item.fromCity + ", " +
item.fromState + " " + item.fromZip;
}
}
...
});
The exact code depend on the format of the input data. The advantage of the usage of beforeProcessing is that it will be called before the data will be processed by jqGrid. So you can do any modification in the data or like in the above.
UPDATED: The code of datatype can be easy implemented in another way using standard jqGrid options. So I suggest to use the following settings:
datatype: "json",
url: "/GetGrid",
postData: {
// add and to the list of parameters sent to the web service
showActive: function () {
return $('#btnFilterActive.pressed').length > 0;
},
showInactive: function () {
return $('#btnFilterActive.pressed').length > 0;
}
},
prmNames: {
// rename some parameters sent to the web service
sort: "sortIndex",
order: "sortDirection",
search: "search",
// don't send nd parameter to the server
nd: null
// you leave the nd is you don't set any "Cache-Control" HTTP header
// I would recommend you to set "Cache-Control: private, max-age=0"
// For example
// HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan(0));
},
serializeGridData: function (postData) {
// control modification of the the data (parameters) which will be sent
// to the web method
if (typeof postData.filters === "undefined") {
postData.filters = "";
}
return JSON.stringify(postData);
},
ajaxGridOptions: { contentType: "application/json" },
jsonReader: {
root: "d.rows",
page: function (obj) { return obj.d.page; },
total: function (obj) { return obj.d.total; },
records: function (obj) { return obj.d.rows.length; },
repeatitems: false
},
loadError: function (jqXHR, textStatus, errorThrown) {
// see an implementation example in the answers
// https://stackoverflow.com/a/6969114/315935
// and
// https://stackoverflow.com/a/5501644/315935
},
colNames:["AddressTo", "AddressFrom"],
colModel:[
{name: "addressTo", ...},
{name: "addressFrom", ...}
],
beforeProcessing: function (data) {
var i, rows, l, item;
data.d = NET.format(data.d); // just correctly format dates
rows = data.d.rows;
l = rows.length;
for (i = 0; i < l; i++) {
item = rows[i];
LoadedDisasters[i] = item;
item.addressTo = item.toStreet + " " + item.toCity + ", " +
item.toState + " " + item.toZip;
item.addressFrom = item.fromStreet+ " " + item.fromCity + ", " +
item.fromState + " " + item.fromZip;
}
}
...
The usage of nd: null with setting of "Cache-Control: private, max-age=0" I described in the answer. You can download the corresponding demo project which use this. In general one needs just include one additional line where you call SetMaxAge
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public MyGridData GetGrid(...) {
HttpContext.Current.Response.Cache.SetMaxAge (new TimeSpan(0));
...
}
See more about caching control you can read here.
I have a view that accepts 2 string parameters and 2 date values. User hits search button and they get filtered output to the screen. This all works perfectly well until a user inputs a string with a space. i.e. they can search for 'waste' but not 'waste oil'.
Interestingly, in the latter, the parameter is ok from Javascript before the call is made. But on entering the controller code it goes form being 'waste oil' on client to 'waste'. When this happens the other parameters get set to NULL crashing the system.
I've tried replacing the spaces if present with '#' character then stripping out and putting back in ' ' on the controller side. This is a messy fudge and only appears to work with one parameter.
There must be a simple explanation for this parameter data loss, any comments much appreciated
Not sure a code example is needed but here it is anyway if it help:
My controller header :
public ActionResult IndexSearch(int? page, string searchText,string searchTextSite,string StartDate,string EndDate)
{
My HTML Javascript :
function Search(sSearchText,sSite) {
sSearchText = sSearchText.toString().replace(" ", "#");
sSite = sSite.toString().replace(" ", "#");
debugger;
alert($("#AbsolutePath").val() + "Waste.mvc/IndexSearch?searchText=" + sSearchText + "&searchTextSite=" + sSite + "&StartDate=" + $('#StartDate').val() + "&EndDate=" + $('#EndDate').val());
$("#ResultsList").load($("#AbsolutePath").val() + "Waste.mvc/IndexSearch?searchText=" + sSearchText + "&searchTextSite=" + sSite + "&StartDate=" + $('#StartDate').val() + "&EndDate=" + $('#EndDate').val(),
function() {
$('#LoadingGif').empty();
});
$('#LoadingGif').empty().html('<img src="' + $("#AbsolutePath").val() + 'Content/images/ajax-loader.gif" alt="Loading image" />');
}
You are not URL encoding your parameters when sending the AJAX request because you are using string concatenations when building the url. You could use the following technique in order to have properly encoded values:
var url = $('#AbsolutePath').val() + 'Waste.mvc/IndexSearch';
var data = {
searchText: sSearchText,
searchTextSite: sSite ,
StartDate: $('#StartDate').val(),
EndDate: $('#EndDate').val()
};
$('#ResultsList').load(url, data, function() {
$('#LoadingGif').empty();
});
Now you will get correct values on the server.