Last few days i was trying to get jqgrid with autocompletion fields to work, now i can get it to work with local data, but as soon as i trying to get data from my controller data didnt get parsed.
View code:
{ name: 'EanNummer', index: 'EanNummer', width: 65, sortable: true, editable: true, edittype: 'text', editoptions: {
dataInit:
function (elem) {
$(elem).autocomplete({ minLength: 0, source: '#Url.Action("GetBrands")' })
.data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + item.Id + ", " + item.Name + "</a>")
.appendTo(ul);
};
}
}
},
if instead of source: url i use source: ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"] for example code works fine and shows up, so something must be wrong with my controller side code
Controller Code:
public JsonResult GetBrands()
{
string vendorId = "";
var username = "";
var name = System.Web.HttpContext.Current.User.Identity.Name;
var charArray = name.Split("\\".ToCharArray());
username = charArray.Last();
vendorId = service.GetVendorIdByUsername(username);
List<String> list = new List<String>();
var brands = service.getBrandsByVendor(vendorId);
var s= (from brand in brands
select new
{
Id = brand.BrandId,
Name = brand.BrandName
}).ToList();
return Json(s);
}
If you use item.Id and item.Name on the client side you should return not the List<String>. Instead of that you should returns the list of new {Id=brand.BrandId, Name=brand.BrandName}. You should just use LINQ instead of foreach:
return Json ((from brand in brands
select new {
Id = brand.BrandId,
Name = brand.BrandName
}).ToList());
UPDATED: I modified for you the demo from the answer and included jQuery UI Autocomplete support in two forms. The standard rendering:
and the custom rendering:
The Autocomplete functionality works in Advanced Searching dialog in the same way like in the Searching Toolbar:
You can download the demo from here.
The server code of the standard autocomplete is
public JsonResult GetTitleAutocomplete (string term) {
var context = new HaackOverflowEntities();
return Json ((from item in context.Questions
where item.Title.Contains (term)
select item.Title).ToList(),
JsonRequestBehavior.AllowGet);
}
It returns array of strings in JSON format. The list of Titles are filtered by term argument which will be initialized to the string typed in the input field.
The server code of the custom autocomplete is
public JsonResult GetIds (string term) {
var context = new HaackOverflowEntities();
return Json ((from item in context.Questions
where SqlFunctions.StringConvert((decimal ?)item.Id).Contains(term)
select new {
value = item.Id,
//votes = item.Votes,
title = item.Title
}).ToList (),
JsonRequestBehavior.AllowGet);
}
It uses SqlFunctions.StringConvert to be able to use LIKE in comparing of the integers. Moreover it returns the list of objects having value the title property. If you would return objects having value the lable properties the values from the lable properties will be displayed in the Autocomplete context menu and the corresponding value property will be inserted in the input field. We use custom title property instead.
The code of the client side is
searchoptions: {
dataInit: function (elem) {
$(elem).autocomplete({ source: '<%= Url.Action("GetTitleAutocomplete") %>' });
}
}
for the standard rendering and
searchoptions: {
sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'],
dataInit: function (elem) {
// it demonstrates custom item rendering
$(elem).autocomplete({ source: '<%= Url.Action("GetIds") %>' })
.data("autocomplete")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a><span style='display:inline-block;width:60px;'><b>" +
item.value + "</b></span>" + item.title + "</a>")
.appendTo(ul);
};
}
}
for the custom rendering.
Additionally I use some CSS settings:
.ui-autocomplete {
/* for IE6 which not support max-height it can be width: 350px; */
max-height: 300px;
overflow-y: auto;
/* prevent horizontal scrollbar */
overflow-x: hidden;
/* add padding to account for vertical scrollbar */
padding-right: 20px;
}
/*.ui-autocomplete.ui-menu { opacity: 0.9; }*/
.ui-autocomplete.ui-menu .ui-menu-item { font-size: 0.75em; }
.ui-autocomplete.ui-menu a.ui-state-hover { border-color: Tomato }
.ui-resizable-handle {
z-index: inherit !important;
}
You can uncomment .ui-autocomplete.ui-menu { opacity: 0.9; } setting if you want to have some small
opacity effect in the autocomplete context menu.
Related
I want to show 30 days in Day View Scheduler with Horizontal Scrollbar. Currently, Horizontal Scrollbar is available only for Timeline View but I want it for Day View as well as Month View.
For Timeline View with Horizontal Scrollbar code:
scheduler.createTimelineView({
name: "timeline",
x_unit: "minute",
x_date: "%H:%i",
x_step: 30,
x_size: 24*7,
x_start: 16,
x_length: 48,
y_unit: sections,
y_property: "section_id",
render: "bar",
scrollable: true,
column_width: 70,
scroll_position:new Date(2018, 0, 15) });
Please share your ideas and Sample links
Thanks in Advance
Try using Custom View. You can remove the default Day view and display your own instead, with the number of days you want to display. This can be done like this:
First in scheduler.config.header set tab "thirty_days" instead of "day":
scheduler.config.header = [
"thirty_days",
"week",
"month",
"date",
"prev",
"today",
"next"
];
The label for the view is set as in:
scheduler.locale.labels.thirty_days_tab = "Days";
Next, set the start date of the viewing interval, as well as viewing templates. It's better to create the custom view in the onTemplatesReady event handler function so that your custom view templates are ready before the scheduler is initialized:
scheduler.attachEvent("onTemplatesReady", () => {
scheduler.date.thirty_days_start = function(date) {
const ndate = new Date(date.valueOf());
ndate.setDate(Math.floor(date.getDate()/10)*10+1);
return this.date_part(ndate);
}
scheduler.date.add_thirty_days = function(date,inc) {
return scheduler.date.add(date,inc*30,"day");
}
const format = scheduler.date.date_to_str(scheduler.config.month_day);
scheduler.templates.thirty_days_date = scheduler.templates.week_date;
scheduler.templates.thirty_days_scale_date = function(date) {
return format(date);
};
});
To add horizontal scrolling to the view, you can place the scheduler inside the scrollable element and give the scheduler the width required to display all columns. You'll need to hide a default navigation panel of the scheduler and create a custom one with HTML, so it would have a correct width and won't be affected by scrolling:
scheduler.xy.nav_height = 0;
scheduler.attachEvent("onSchedulerReady", function () {
const navBar = scheduler.$container.querySelector(".dhx_cal_navline").cloneNode(true);
navBar.style.width = "100%";
document.querySelector(".custom-scheduler-header").appendChild(navBar);
document.querySelectorAll(".custom-scheduler-header .dhx_cal_tab").forEach(function (tab) {
tab.onclick = function () {
const name = tab.getAttribute("name");
const view = name.substr(0, name.length - 4);
scheduler.setCurrentView(null, view);
};
});
document.querySelector(".custom-scheduler-header .dhx_cal_prev_button").onclick = function () {
const state = scheduler.getState();
scheduler.setCurrentView(scheduler.date.add(state.date, -1, state.mode));
};
document.querySelector(".custom-scheduler-header .dhx_cal_next_button").onclick = function () {
const state = scheduler.getState();
scheduler.setCurrentView(scheduler.date.add(state.date, 1, state.mode));
};
document.querySelector(".custom-scheduler-header .dhx_cal_today_button").onclick = function () {
scheduler.setCurrentView(new Date());
};
scheduler.attachEvent("onBeforeViewChange", (oldView, oldDate, newView, newDate) => {
const innerContainer = document.getElementById("scheduler_here");
if (newView === "thirty_days") {
innerContainer.style.width = "3000px";
} else {
innerContainer.style.width = "100%";
}
return true;
});
scheduler.attachEvent("onViewChange", function (view, date) {
const dateLabel = document.querySelector(".custom-scheduler-header .dhx_cal_date");
const state = scheduler.getState();
dateLabel.innerHTML = scheduler.templates[view + "_date"](state.min_date, state.max_date);
document.querySelectorAll(".custom-scheduler-header .dhx_cal_tab").forEach(function(tab) {
tab.classList.remove("active");
});
const activeTab = document.querySelector(".custom-scheduler-header ." + view + "_tab");
if (activeTab) {
activeTab.classList.add("active");
}
});
});
Styles that you will need:
.custom-scheduler-header .dhx_cal_navline{
display: block !important;
height: 60px !important;
}
.custom-scheduler-header .dhx_cal_navline.dhx_cal_navline_flex{
display: flex !important;
}
.dhx-scheduler {
height: 100vh;
width: 100vw;
position: relative;
overflow: hidden;
background-color: #fff;
font-family: Roboto, Arial;
font-size: 14px;
}
.dhx_cal_container .dhx_cal_navline {
display: none;
}
Please see an example: https://snippet.dhtmlx.com/znd7ffiv
You may need to fix the hour scale so that it remains visible when scrolling horizontally on the calendar. I did not implement this in the example, I think that this can be done in the same way as for the navigation panel. If you need, write to me and I will send an update in a few working days.
As for the "Month" view, the approach is the same as for the "Day" view.
I'm working with a Kendo treelist widget, and disappointed to see there's no rowTemplate option as there is on the Kendo grid.
I see a columnTemplate option (i.e. http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#configuration-columns.template ), but this will affect the entire column.
However, I need to drill into each cell value and set a css color property based on a ratio ( i.e. If value/benchmark < .2, assign <span style='color:red;'> , but my color value is dynamic.
There's a dataBound: and dataBinding: event on the treelist, but I'm still trying to figure out how to intercept each cell value and set the color once I've done my calculation.
var treeOptions = {
dataSource: ds,
columns: colDefs,
selectable: true,
scrollable: true,
resizable: true,
reorderable: true,
height: 320,
change: function (e) {
// push selected dataItem
var selectedRow = this.select();
var row = this.dataItem(selectedRow);
},
dataBound: function (e) {
console.log("dataBinding");
var ds = e.sender.dataSource.data();
var rows = e.sender.table.find("tr");
}
};
and this is where I'm building out the `colDefs' object (column definitions):
function parseHeatMapColumns(data, dimId) {
// Creates the Column Headers of the heatmap treelist.
// typeId=0 is 1st Dimension; typeId=1 is 2nd Dimension
var column = [];
column.push({
"field": "field0",
"title": "Dimension",
headerAttributes: { style: "font-weight:" + 'bold' + ";" },
attributes : { style: "font-weight: bold;" }
});
var colIdx = 1; // start at column 1 to build col headers for the 2nd dimension grouping
_.each(data, function (item) {
if (item.typeId == dimId) {
// Dimension values are duplicated, so push unique values (i.e. trade types may have dupes, whereas a BkgLocation may not).
var found = _.find(column, { field0: item.field0 });
if (found == undefined) {
column.push({
field: "field2",
title: item.field0,
headerAttributes: {
style: "font-weight:" + 'bold'
}
,template: "<span style='color:red;'>#: field2 #</span>"
});
colIdx++;
}
}
});
return column;
}
**** UPDATE ****
In order to embed some logic within the template :
function configureHeatMapColumnDefs(jsonData, cols, model) {
var colDef = '';
var dimId = 0;
var colorProp;
var columns = kendoGridService.parseHeatMapColumns(jsonData, dimId);
// iterate columns and set color property; NB: columns[0] is the left-most "Dimension" column, so we start from i=1.
for (var i = 1; i <= columns.length-1; i++) {
columns[i]['template'] = function (data) {
var color = 'black';
if (data.field2 < 1000) {
color = 'red';
}
else if (data.field2 < 5000) {
color = 'green';
}
return "<span style='color:" + color + ";'>" + data.field2 + "</span>";
};
}
return columns;
}
Advice is appreciated.
Thanks,
Bob
In the databound event you can iterate through the rows. For each row you can get the dataItem associated with it using the dataitem() method (http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#methods-dataItem)
Once you have the dataitem, calculate your ration and if the row meets the criteria for color, change the cell DOM element:
dataBound: function (e) {
var that = e.sender;
var rows = e.sender.table.find("tr");
rows.each(function(idx, row){
var dataItem = that.dataItem(row);
var ageCell = $(row).find("td").eq(2);
if (dataItem.Age > 30) {
//mark in red
var ageText = ageCell.text();
ageCell.html('<span style="color:red;">' + ageText + '</span>');
}
}
DEMO
UPDATE: you can also do this with a template:
$("#treelist").kendoTreeList({
dataSource: dataSource,
height: 540,
selectable: true,
columns: [
{ field: "Position"},
{ field: "Name" },
{ field: "Age",
template: "# if ( data.Age > 30 ) { #<span style='color:red;'> #= data.Age # </span> #}else{# #= data.Age # #}#"
}
],
});
DEMO
I have two Extjs Comboboxes
var cb1 = new Ext.form.ComboBox({
fieldLabel: 'Combobox1',
width: 100,
listeners:{
scope: this,
'select': this.reset
}
});
var cb2 = new Ext.form.ComboBox({
fieldLabel: 'Combobox2',
width: 100,
baseParams: { loadInitial: true, cb1Val: this.cb1.getValue() } // Here I want to get selected value of cb1
listeners:{
scope: this,
'select': this.reset
}
});
I am using this.cb1.getValue() to get selected value of cb1 but I am getting blank value here.
Can anyone tell me what I am doing wrong here.
I think combo 2 is not able to get value of combo 1 as its not loaded while you are calling its value in baseParams. I would recommend this approach in your case -
var cb1 = new Ext.form.ComboBox({
fieldLabel: 'Combobox1',
width: 100,
**id : "combo_1",** // ID property added
listeners:{
scope: this,
'select': this.reset
} });
// Previous code
...
listeners : {
select : function(combo, rec, rind) {
var combo2_val = Ext.getCmp("id_of_combo_1").getValue();
}
Here, on the select renderer of second combo, the value of first should be set in combo2_val. To be more precise, you can also set default value for combo 1. Instead of using ID, you can directly use variable cb1 directly.
Hope this should give you a way.
I'm having some trouble adding toolbar options to the CKEditor4 inline toolbar option. I've been reading the docs and still can't figure out where my problem is.
I'm creating a div on the fly, then adding the CKEditor to the div. Everything works fine, but I want to remove some of the tool bar options and add some other ones. When I add parameters to the inline() call nothing changes?
Here is how I create the instance on the fly:
.on('dblclick', function(e){
e.preventDefault();
e.stopPropagation();
ed.ck_restore();
ed.ck_active_block = $(this).attr("id");
ed.ck_block_data = $(this).html();
var block_width = $(this).css("width");
var block_height = $(this).css("height")+20;
var block_padding_top = $(this).css("padding-top");
var block_padding_right = $(this).css("padding-right");
var block_padding_bottom = $(this).css("padding-bottom");
var block_padding_left = $(this).css("padding-left");
var padding = 'padding-top: '+block_padding_top+';padding-right: '+block_padding_right+';padding-bottom: '+block_padding_bottom+';padding-left: '+block_padding_left+';';
var editor = '<div id="edit" contenteditable="true" style="margin-top: -'+block_padding_top+'; margin-left: -'+block_padding_left+';'+padding+' width: '+block_width+'; height: '+block_height+';background-color: #fff;position: absolute;">'+ed.ck_block_data+'</div>';
$("#"+ed.ck_active_block).prepend(editor);
if(CKEDITOR.instances.edit)
{
CKEDITOR.instances.edit.destroy(); //remove any previously created instances
}
CKEDITOR.inline("edit",
[CKEDITOR.config.fontSize_style = {
element: 'span',
styles: { 'font-size': '#(size)' },
overrides: [ {
element: 'font', attributes: { 'size': null }
}]
}]
);
$("#edit").click(function(e){e.stopPropagation();}).focus();
$("w_save").text("1");
});
http://docs.ckeditor.com/#!/api/CKEDITOR-method-inline
The docs imply I can pass a configuration parameter to change the options, but I'm missing something and after 3 hours of trying I need a bit of help.
Any help is appreciated.
Thanks.
I don't know what that meant to be:
CKEDITOR.inline("edit",
[CKEDITOR.config.fontSize_style = {
element: 'span',
styles: { 'font-size': '#(size)' },
overrides: [ {
element: 'font', attributes: { 'size': null }
}]
}]
);
It is invalid JavaScript code. Have you checked your JS console?
Anyway, CKEDITOR.inline accepts two arguments - name and config object.
CKEDITOR.inline( 'edit', {
fontSize_style: {
element: 'span',
styles: { 'font-size': '#(size)' },
overrides: [
{ element: 'font', attributes: { 'size': null } }
]
},
language: 'pl',
removeButtons: 'Bold,Italic' // or set toolbar or toolbarGroups.
} );
Thanks for the reply Reinmar. I was able to find another solution. Here is the code for others:
CKEDITOR.inline("edit",{customConfig : "mycustomConfig.js"});
This referenced a custom config file, I just pulled it from an example config on the CKEditor site and changed some of the options. Works now.
Is there a way to create a custom field that has multiple input elements? I'm consulting the documentation and creating a single input element is pretty straight forward, but I'm not exactly sure how you'd add more than one.
Has anyone crossed this bridge before? If so, how did you do it?
Here's some sample code:
...
{name: 'Dimensions', index: 'Dimensions', hidden: true, editable: true,
edittype: 'custom', editoptions: {custom_element: dimensionsElement,
custom_value: dimensionsValue}, editrules: {edithidden: true}},
...
function dimensionsElement(value, options) {
var el = document.createElement("input");
el.type = "text";
el.value = value;
return el;
}
function dimensionsValue(elem) {
return $(elem).val();
}
You can use jQuery to create multiple input elements. So if your field is for example a persons full name you can use following
{ name: 'FullName', editable: true, edittype: 'custom', width: 300,
editoptions: {
custom_element: function(value, options) {
// split full name to the first and last name
var parts = value.split(' ');
// create a string with subelements
var elemStr = '<div><input id="'+options.id +
'_first" size="10" value="' + parts[0] +
'" /></br><input id="'+options.id + '_last' +
'"size="20" value="' + parts[1] + '" /></div>';
// return DOM element from jQuery object
return $(elemStr)[0];
},
custom_value: function(elem) {
var inputs = $("input", $(elem)[0]);
var first = inputs[0].value;
var last = inputs[1].value;
return first + ' '+ last;
}
}},
It is of cause a raw code fragment and you should improve the layout of input elements (the value of size attribute for example). It shows the main concept of building of custom edit elements.
UPDATED: If you use custom editing it is important to use recreateForm: true parameter (see http://www.trirand.com/jqgridwiki/doku.php?id=wiki:form_editing). See jqgrid - Set the custom_value of edittype: 'custom' for details.