nested autocomplete with selectize plugin - javascript

I am using the query-builder plugin in combination with selectize.js plugin to have autocomplete in my query-builder enabled and it works perfectly.
What I would like to know is whether there is any out of the box way to achieve nested autocomplete with selectize.js, or if not any, which part of code could I customize in the plugin to achieve this functionality.
Example of current autocomplete
Code of current autocomplete
values = [{...}] //values holds the json array of the example
plugin = 'selectize';
input = 'text';
plugin_config = {
valueField: 'value',
labelField: 'value',
searchField: ['value'],
sortField: 'value',
nesting: true,
searchFieldOptions: [{nesting: true}],
create: true,
maxItems: 1,
onInitialize: function() {
var that = this;
values.forEach(function(item) {
that.addOption(item);
});
}
};
valueSetter = function(rule, value) {
rule.$el.find('.rule-value-container input')[0].selectize.setValue(value);
}
JSON example
[{
"value": "AnyRole",
"arrayofobjs": [{
"value": "firstobj"
},
{
"value": "secondobj"
}
]
},
{
"value": "Administrator",
"arrayofobjs": [{
"value": "firstobj"
},
{
"value": "secondobj"
}
]
}]
Considering the json sample above, I would like to search inside arrayofobjs when typing the . notation after an option of object values as shown below.
a
AnyRole
Administrator
Manager
and when selecting f.e 'Administrator' and type the dot notation
Administrator.
firstobj
secondobj
The same way editors do with objects.
Is there anything out of the box? I have searched in the selectize.js examples as well as into other threads on GitHub but did not find anything related to it. In case there is not any, I could make a custom solution myself but it would be great if anyone gives me any tips on which part of code and what should I do, thanks in advance :)

Related

Unflattening line items in inputData when rendered by function

I have dynamic children input fields that need to be rendered in a function, but when they are, then they are not included in inputData properly/not under the parent input field's key. When the children are included directly in the inputFields, it works as expected, but I can't use a function within the children array with Zapier.
Here is the inputData currently, when the line items are rendered in a function, the LI_ denotes that it is a child input key -
"inputData": {
"supplier": "1",
"LI_budget": 1,
"LI_tax": 1,
"company": "1",
"currency": "1",
"LI_price": "1",
"LI_description": "1"
}
I'm expecting ("parent" is the inputField parent key here):
"inputData": {
"supplier": "1",
"parent": [{
"LI_budget": 1,
"LI_tax": 1,
"LI_price": "1",
"LI_description": "1"
}],
"company": "1",
"currency": "1",
}
This is the function I'm using to pull in the parent and children input fields:
const getLineItems = async (z, bundle) => {
let lineItem = {
key: 'parent',
children: [{
key: 'LI_description',
label: 'Description',
required: true
},
{
key: 'LI_budget',
required: true,
label: 'Budget',
dynamic: 'budget.id'
},
{
key: 'LI_price',
required: true,
type: 'number',
label: 'Unit price',
helpText: 'Example: 50.25'
},
{
key: 'LI_tax',
required: true,
label: 'Tax Rate',
dynamic: 'tax_rate.id'
},
]
}
return [lineItem];
};
There are dynamic fields generated in the getLineItems function that I took out to simplify. TIA
Caleb here from Zapier Platform Support. This is a tough one! We have a pretty long-standing issue report on our platform for supporting custom fields with parent keys (it boils down to a chicken vs the egg problem that really makes my head spin when I read the discussion on the issue). Your inputFields function is spot-on, it's just a matter of properly storing it in the bundle on our part.
I think we could cobble together a workaround to unflatten it. Before I do that though, could you give this a test in the editor and submit actual line items from a previous step to this step? I'm not sure what the inputData looks like (e.g. if multiple items are split like 1,2,3 or in some other fashion). If you want to iterate on this, it might be better to switch over to our public developer Slack (http://zpr.io/ttvdr); then we can post the results here for the next person to run into this. 😁

Add fields in DevExpress Pivot using AngularJS

I'm looking at this template to build a web application: https://js.devexpress.com/Demos/WidgetsGallery/Demo/PivotGrid/FieldChooser/AngularJS/Light/
In the example there are static data. I have to retrieve them from the server. So, I wrote this:
$scope.testData = [];
$scope.pivotGridDataSource = new DevExpress.data.PivotGridDataSource({
fields: [{
caption: "Nome",
dataField: "fullName",
area: "row"
}, {
caption: "Country",
dataField: "country",
area: "column"
}, {
caption: "Count",
dataField: "countOne",
dataType: "number",
summaryType: "sum",
area: "data"
}],
store: $scope.testData
});
$scope.pivotGridOptions = {
allowSortingBySummary: true,
allowSorting: true,
allowFiltering: true,
showBorders: true,
dataSource: $scope.pivotGridDataSource,
fieldChooser: {
enabled: false
}
},
$scope.fieldChooserOptions = {
dataSource: $scope.pivotGridDataSource,
texts: {
allFields: "All",
columnFields: "Columns",
dataFields: "Data",
rowFields: "Rows",
filterFields: "Filter"
},
width: 400,
height: 400,
bindingOptions: {
layout: "layout"
}
};
// Now I call the server to retrieve data
$scope.getTestData = () => {
$scope.testData.length = 0;
result.forEach(e => {
$scope.testData.push(e);
);
$scope.pivotGridDataSource.reload();
}
$scope.getTestData();
The problem is that when the data are loaded, in the Fields below it shows just the fields written at the beginning (so the name, the count and the country). But I saw in the demo that it should be display ALL parameters of the object.
For example, if the object is so structured:
{ "name": "Test1", "country": "Germany", "creationDate": "xxx", "surname": "yyy" }
So, I expect that in the fields there should be ALL parameters, so name, country, creationDate, surname. So, I did this at the beginning:
I changed $scope.testData = [] into:
$scope.testData = [{ "name": "", "country": "", "creationDate": "", "surname": "" }]
so the component will preparare all fields. And this works. But what if the server gives me back an Object that has another parameters? How can I display them?
I tried so after the calling and before the reload():
let fields = $scope.pivotGridDataSource.fields();
let newField = {
llowExpandAll: false,
allowFiltering: true,
allowSorting: true,
allowSortingBySummary: true,
caption: "This is a new field",
dataField: "newField",
dataType: "string",
displayFolder: "",
index: fields.length
}
$scope.pivotGridDataSource.fields().push(newField);
$scope.pivotGridDataSource.reload();
But it doesn't work yet. Worse, it does not even initialize the Pivot.
The fieldChooser uses the store fields, in this case $scope.testData fields, in your code I see your store is first declared (as null or with some format as you described) and then you have a function to fill it.
I don't know how your code looks and why you create your store that way, but that is basically your problem (the flow).
In the sample code the flow is:
Store with data (static in this case)
PivotGridDataSource
FieldChooser
In your code the flow is:
Store (empty)
PivotGridDataSource
FieldChooser
Store (fill) --> at this point your FieldChooser has been initialized with the fields of the empty version of your store so not much to do (in Jquery you could re-create your object, you dan do it using Jquery within AngularJs see a simple code sample here and below)
$('#chartContainer').dxChart('instance').dispose();
$('#chartContainer').dxPieChart({
...
});
To avoid all of this you can just use the DevExpress.data.CustomStore and your flow will be basically identical to the demo.

Kendo, kendoDropDownList, _selectedValue, always the first option

This is probably easy but I'm stuck.
I have a function that works with a kendoDropDownList and I cannot retrieve the value of the selectedIndex. Ignoring what the function actually does, can someone explain this?
function setDocTypeAssociates(event){
var dropdownlist = $("#type_doma_ky").data("kendoDropDownList");
console.log(dropdownlist);
console.log(dropdownlist._selectedValue);
console.log(dropdownlist.selectedIndex);
...
The result of those three console.log()s you can see in the attached screendump.
Why are the values correct (65 and 4) in the object, yet incorrect (67 and 0) when I dump them individually?
It is really hard to say why you get these results, I personally tried to reproduce them and was unable.
Any way the best way to get your data would be:
var dropdownlist = $("#list").data("kendoDropDownList");
console.log(dropdownlist);
console.log(dropdownlist.text());
console.log(dropdownlist.value());
console.log(dropdownlist.selectedIndex);
with text() and value() functions.
In general Telerik does not recommend using fields that start with underscore because they are setup for internal use and might change. For example in the latest version of Kendo UI _selectedValue returns undefined.
I have created working example for your reference.
http://dojo.telerik.com/eNUkU
look at this fiddle:
(https://jsfiddle.net/cr1v6cvh/1/)
Get Data
<script>
$("#btnGetData").kendoButton({
click: function (event){
var dropdownlist = $("#dataList").data("kendoDropDownList");
console.log(dropdownlist);
console.log(dropdownlist.text());
console.log(dropdownlist.value());
console.log(dropdownlist.selectedIndex);
}
})
$(document).ready(function() {
$(".ddlData").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: [
{ text: "data 1", value: "1" },
{ text: "data 2", value: "2" },
{ text: "data 3", value: "3" },
{ text: "data 4", value: "4" }
]
});
});
</script>

How to create Tree with checkboxes using JSON data with Parent Child Relation?

I have JSON data and that JSON data has parent child relation . I Want to create tree structure from it. i found many plugins and libraries but i can't found my requirement . I am getting this JSON data using PHP script.
Here is image that has tree structure that i want to create . i'm stuck at it.I know JSON is not as displayed in image but i only want to show you what a tree should look like .How to create tree like in image.All i want is javascript code to handle and create this type of structure of tree . Working example is must & much appreciated.
You can use JSON format as you like and tree should be collapsible.Also provide required JSON format for it.
and my JSON data as follows :
{
"2":
{
"5": "Wrist Watch"
},
"5":
{
"9": "Men's"
},
"18":
{
"3": "Clothing"
},
"28":
{
"1": "Perfumes"
},
"29":
{
"7": "Laptop",
"10": "Tablets"
},
"30":
{
"8": "Mobile"
},
"31":
{
"2": "Books"
},
"33":
{
"6": "Electronics"
},
"34":
{
"4": "Home & Kitchen\n"
}
}
If you want to roll your own, the keyword in "trees" is recursion. It needs to support any depth of data and the code and data should both support recursion.
This means your JSON data should be a recursive structure, where each node looks the same (and looks something like this):
{
id: 1, // data id
title: "title", // display title
children: [ // list of children, each with this same structure
// list of child nodes
]
}
Note: I have changed the sample data to contain more depth as 2 levels never shows up recursion problems.
e.g.:
{
id: 0,
title: "root - not displayed",
children: [{
id: 1,
title: "Option 1",
children: [{
id: 11,
title: "Option 11",
children: [{
id: 111,
title: "Option 111"
}, {
id: 112,
title: "Option 112"
}]
}, {
id: 12,
title: "Option 12"
}]
}, {
id: 2,
title: "Option 2",
children: [{
id: 21,
title: "Option 21"
}, {
id: 22,
title: "Option 22"
}]
}, {
id: 3,
title: "Option 3",
children: [{
id: 31,
title: "Option 31"
}, {
id: 32,
title: "Option 32"
}]
}]
}
The recursive function looks like this:
function addItem(parentUL, branch) {
for (var key in branch.children) {
var item = branch.children[key];
$item = $('<li>', {
id: "item" + item.id
});
$item.append($('<input>', {
type: "checkbox",
name: "item" + item.id
}));
$item.append($('<label>', {
for: "item" + item.id,
text: item.title
}));
parentUL.append($item);
if (item.children) {
var $ul = $('<ul>').appendTo($item);
addItem($ul, item);
}
}
}
JSFiddle: http://jsfiddle.net/0s0p3716/188/
The code recurses the structure, adding new ULs and LIs (with checkbox etc ) as it goes. The top level call just provides the initial root starting points of both the display and the data.
addItem($('#root'), data);
The end result looks like this:
If you want to toggle visibility, based on the checked state, use this:
$(':checkbox').change(function () {
$(this).closest('li').children('ul').slideToggle();
});
If you also want the labels to toggle the checkboxes, use this:
$('label').click(function(){
$(this).closest('li').find(':checkbox').trigger('click');
});
Note: I have only provided the most basic of styling as that will typically be "to taste". Examples in links were shown in another answer.
-- updated:
amended: possible wrong ids for items 31 & 32?
function for better selection and deselection(for parents cascading into child nodes):
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
$(this).find(':checkbox').trigger('click');
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
-- Update the fiddle with this as shown here(JsFiddle) and it will work better and also will allow you to click the text to expand without selecting at the same time - I know I find this far more useful. It will help (and this is personal preference) you to see what values and options are available without having to select the first.
The thing with programming is: existing libraries and tools rarely do exactly what you need. It's always up to you to convert the input data into exactly the format they expect and then the output data into the format you need. Occasionally this conversion requires more effort than writing your own code instead of a library function - this seems to be one of those occasions.
As #philosophocat already noted, the best way to present such a tree in HTML markup would be nested lists. All you need is iterate through the JSON data recursively and create the corresponding elements:
function createList(data)
{
var result = document.createElement("ul");
for (var key in data)
{
if (!data.hasOwnProperty(key) || key == "_title")
continue;
var value = data[key];
var item = createItem(key, typeof value == "string" ? value : value._title);
if (typeof value == "object")
item.appendChild(createList(value));
result.appendChild(item);
}
return result;
}
function createItem(value, title)
{
var result = document.createElement("li");
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("name", "selection");
checkbox.setAttribute("value", value);
result.appendChild(checkbox);
result.appendChild(document.createTextNode(title));
return result;
}
document.body.appendChild(createList(jsonData));
Note that the order in which the items appear is "random" here, as object keys are generally unordered. You can change the code above to sort the keys somehow, or you can change the data to use arrays and define an order. I also added a "_title" property to the data to make sure the categories are labeled - your data doesn't have any labels at all for the categories.
Now you need to style the lists in such a way that they look like a tree. The obvious solution is using the list-style-image CSS property to replace the usual bullet points by a grid lines image. However, that doesn't work for nested lists - there you need to show multiple images, vertical lines from the higher-level lists as well as the image actually belonging to the current list item.
This can be solved by using background images for the list items instead, these background images will be shown next to sublists as well then. Here are the example styles I've got:
ul
{
padding: 0;
list-style-type: none;
font-size: 14px;
}
li
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAABkCAYAAABdELruAAAAP0lEQVR42u3PQQoAIAgEQP3/o6t7JAhdolkQD4sMZuwZazKKlGXniHRDOu6HfyKRSCQSiUQikUgkEolEIv0rTc/fNmQ78+lPAAAAAElFTkSuQmCC);
background-repeat: no-repeat;
padding-left: 13px;
}
li:last-child
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAHUlEQVR42mNkwAT/gZiRAQ/AK0mKplGbqGETThoACFgJCVdBEqAAAAAASUVORK5CYII=);
}
li > ul
{
margin-left: 5px;
}
Note that this will still get ugly if the sublist is too high - the height of the background image I used is merely 100px. This can be solved by using a larger background image of course. A cleaner alternative would be using border-image-slice CSS property but that one is currently only supported in Firefox.
Fiddle for this code
Edit: This article goes into more detail on styling nested lists like a tree. While the approach is similar, it manages to avoid the image size issues I mentioned above by using a separate image for the vertical line which can be repeated vertically. On the downside, that approach looks like it might only work with solid lines and produce artifacts if applied to dotted lines.
Use http://www.jstree.com/. This library provides each function I ever need when working with trees and javascript.
You simple have to change your json-response according to the given format (http://www.jstree.com/docs/json/):
{
id : "string" // will be autogenerated if omitted
text : "string" // node text
icon : "string" // string for custom
state : {
opened : boolean // is the node open
disabled : boolean // is the node disabled
selected : boolean // is the node selected
},
children : [] // array of strings or objects
li_attr : {} // attributes for the generated LI node
a_attr : {} // attributes for the generated A node
}
Set up the javascript and include all required files and there you go.
I just skip repeating the documentation by referring to it: http://www.jstree.com/
I'm using DynaTree for an internal site at work and it works fantastic.
Download DynaTree
Format your JSON as such (taking your screenshot as an example):
{
"title": "Sports & Outdoors",
"isFolder": true,
"key": "0",
"children": [
{
"title": "Fitness Accessories",
"key": "1",
"isFolder": true,
"children": [
{
"title": "Fitness Accessories",
"key": "2",
"isFolder": true,
"children": [
{
"title": "Pedometer & Watches",
"key": "3"
}
]
}
]
}
]
}
Run this JS on page load:
$("#buildTree").dynatree({
onActivate: function (node) {
// A DynaTreeNode object is passed to the activation handler
// Note: we also get this event, if persistence is on, and the page is reloaded.
leftActiveNodeKey = node.data.key;
},
persist: false,
checkbox: true,
selectMode: 3,
children: $.parseJSON(response.d)
});
To get the selected nodes you can use:
var selectedNodes = $("#buildTree").dynatree("getTree").getSelectedNodes();
Dynatree is pretty customization, both in look and function. Read through the documentation for the settings you need.
Check these sites.Hope this helps.
http://www.jstree.com/docs/json/
http://www.jeasyui.com/documentation/tree.php
http://jqwidgets.com/jquery-widgets-demo/demos/jqxtree/index.htm#demos/jqxtree/checkboxes.htm
#Gone Coding's example is excellent, but the child check boxes will not show as 'uncheked' even though the checked attribute is removed, as rendered in Chrome.
If you add,
$(this).prop('checked', false);
to the code, so it reads as
$(function () {
addItem($('#root'), data);
$(':checkbox').click(function () {
var matchingId = $(this).attr('id');
if ($(this).attr('checked'))
{
$('input[id*=' + matchingId +']').each(function() {
$(this).removeAttr('checked');
$(this).prop('checked', false);
$(this).prop('checked', $(this).attr('checked'));
return;
});
}
else {
$('input[id*=' + matchingId +']').each(function() {
$(this).attr('checked', 'checked');
$(this).prop('checked', $(this).attr('checked'));
});
}
});
$('label').click(function(){
$(this).closest('li').children('ul').slideToggle();
});
});
the child check boxes will fill or clear when the user makes a change.

Sorting order of Groups in kendo ui grid

Here I have written stored procedure for getting CategoryName values based on id, Values are coming like India, America, Brazil up to service, But in UI section values are in automatically sorting in alphabetical order displaying groups like America, Brazil,India. I wanted to show as in order display like India, America, Brazil format. What am I doing wrong? Thanks in advance.
$(document).ready(function () {
var grid = $("#grid").kendoGrid({
dataSource: {
type: "GET",
transport: {
read: {
url: "some url placed here",
dataType: "jsonp"
}
},
pageSize: 20,
serverSorting: false,
group: {
field: "CategoryName",
aggregates: [{
field: "abc",
aggregate: "count"
}, {
field: "def",
aggregate: "sum"
}, {
field: "ghi",
aggregate: "sum"
}]
},
aggregate: [{
field: "abc",
aggregate: "count"
}, {
field: "def",
aggregate: "sum"
}, {
field: "ghi",
aggregate: "sum"
}]
},
columns: [
//column section goes here.....
],
sortable: false
//...
});
});
I remember somewhere in the kendo ui documentation (may be datasource > groups) it said that, if you define groups, the grouping requires the sorted data.. Remove all your groups and display the data in plain vanilla grid and see if some automatic sorting is applied.
This is a complete guess, but have you tried setting the ServerSorting property to true?
Kendo UI Grid Grouping gives you ListSortDirection.Ascending sorting by default. If you want to do something else you have to set it. If you are using the WebApi interface and generating a kendoRequest for the Kendo.mvc.dll method .ToDataSourceResult(kendoRequest); then you may try something like this:
var sort = kendoRequest.Sorts.FirstOrDefault();
var group = kendoRequest.Groups.FirstOrDefault();
if(sort != null && group != null) {
if(sort.Member == group.Member && sort.SortDirection == ListSortDirection.Descending) {
kendoRequest.Groups[0].SortDirection = sort.SortDirection;
}
}
That way the Sort feature from the Grid affects the Group by column when they match.

Categories

Resources