In jsTree, how can we have nodes initially selected after replacing tree? - javascript

In jsTree, I want to draw a new tree replacing the previous one and have nodes initially selected in the new tree.
In the code below, I confirmed that state : {opened : true} made the node initially opened and state : {disabled : true} made the node initially disabled, so I thought state : {selected : true} works too, but actually it is not.
Please note that specifying state : {selected : true} when calling $('#using_json').jstree({...}); does result in the node selected as described in https://www.jstree.com/docs/json/. Then, I wonder why state : {selected : true} does not work when I replace a existing tree with a new tree (while state : {opened : true} and state : {disabled : true} are working).
How can we achieve nodes to be initially selected after replacing tree?
$('#using_json').jstree({ 'core' : {
data : [
{
text : 'Previous root node',
}
]
} });
const newData = [
{
text : 'New root node (Initially opened)',
state : {
opened : true, //'opened' takes effect after refresh
},
children : [
{ text : 'Child 1 (Initially disabled)',
state : {
disabled : true, //'disabled' takes effect after refresh
}
},
{ text : 'Child 2 (Intended to be selected initially but failing)',
state : {
selected : true //'selected' does NOT take effect after refresh
}
}
]
}
]
$('#using_json').jstree(true).settings.core.data = newData;
$('#using_json').jstree(true).refresh(true);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/themes/default/style.min.css" />
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/jstree.min.js"></script>
<div id="using_json"></div>
</body>
</html>

You could try using the select_node config property when you initialize the tree, which you could do just once. For this you need to add some IDs to your nodes so you can then reference the selected node:
$('#using_json').jstree({
'core': {
select_node: 'c2',
data: [{
text: 'Root node after Refresh (Opened)',
state: {
opened: true, //'opened' takes effect after refresh
},
children: [{
text: 'Child 1 (Disabled)',
id: 'c1',
state: {
disabled: true, //'disabled' takes effect after refresh
}
}, {
text: 'Child 2 (Intended to be selected but failing)',
id: 'c2',
state: {
selected: true //'selected' does NOT take effect after refresh
}
}]
}]
}
});
//$('#using_json').jstree(true).settings.select_node = 'c2';
//$('#using_json').jstree(true).refresh(true);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/themes/default/style.min.css" />
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/jstree.min.js"></script>
<div id="using_json"></div>
</body>
</html>
Check out this answer also.
Alternative with refresh
Since OP needs to keep the initial code structure (init -> change config data -> refresh) an alternative solution would be to "force" selection by using the callback of the refresh event:
$('#using_json').jstree({
'core': {
data: [{
text: 'Previous root node',
}]
}
});
const newData = [{
text: 'New root node (Initially opened)',
state: {
opened: true, //'opened' takes effect after refresh
selected: true
},
children: [{
text: 'Child 1 (Initially disabled)',
id: 'c1',
state: {
disabled: true, //'disabled' takes effect after refresh
}
}, {
text: 'Child 2 (Intended to be selected initially but failing)',
id: 'c2',
state: {
selected: true //'selected' does NOT take effect after refresh
}
}]
}];
$('#using_json').jstree().settings.core.data = newData;
//$('#using_json').jstree(true).settings.select_node = 'c2';
$('#using_json').jstree(true).refresh(true);
$('#using_json').on("refresh.jstree", function(e) {
$('#using_json').jstree('select_node', 'c2');
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/themes/default/style.min.css" />
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.4/jstree.min.js"></script>
<div id="using_json"></div>
</body>
</html>

Related

href links in the array object

I am using Grid.js library to build the tables in the wordpress website. Searched for a lot of documentation but unable to find how to add links to the names in the first column to open in a new tab which is the array object.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link
href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css"
rel="stylesheet"
/>
<title>Grid.js Hello World</title>
</head>
<body>
<h1>
Grid.js Hello World
</h1>
<div id="wrapper"></div>
<script src="https://unpkg.com/gridjs/dist/gridjs.umd.js"></script>
<script src="src/index.js"></script>
</body>
</html>
JS file:
new gridjs.Grid({
columns: ["Name", "Email", "Phone Number"],
search: true,
data: [
["John", "john#example.com", "(353) 01 222 3333"],
["Mark", "mark#gmail.com", "(01) 22 888 4444"],
["Eoin", "eoin#gmail.com", "0097 22 654 00033"],
["Sarah", "sarahcdd#gmail.com", "+322 876 1233"],
["Afshin", "afshin#mail.com", "(353) 22 87 8356"]
]
}).render(document.getElementById("wrapper"));
Output
View Code in Sandbox
You can add custom HTML using the formatter option and the gridjs.html() function. For example:
new gridjs.Grid({
// Converted the columns to objects, instead of strings, to pass options
columns: [
{ name: "id", hidden: true },
{
name: "Name",
// Added a `formatter` function
formatter: (cell, row) => {
// Uses the `html` function to add elements
// Note that we're pulling a value for the link from the
// data set as well for a more complete, real-world example
return gridjs.html(
`<a href='mypage.html?id=${row.cells[0].data}'>${cell}</a>`
);
}
},
{
name: "Email",
formatter: (cell, row) => {
return gridjs.html(`<a href='mailto:${row.cells[2].data}'>${cell}</a>`);
}
},
{ name: "Phone Number" }
],
search: true,
// Added unique id, per OP's comments
data: [
[1, "John", "john#example.com", "(353) 01 222 3333"],
[2, "Mark", "mark#gmail.com", "(01) 22 888 4444"],
[3, "Eoin", "eoin#gmail.com", "0097 22 654 00033"],
[4, "Sarah", "sarahcdd#gmail.com", "+322 876 1233"],
[5, "Afshin", "afshin#mail.com", "(353) 22 87 8356"]
]
}).render(document.getElementById("wrapper"));
Updated example using unique id, per OP's comments
Working CodeSandbox: https://codesandbox.io/s/gridjs-hello-world-forked-u52kyg?file=/src/index.js
Source: https://gridjs.io/docs/examples/html-cells
You can use a custom cell formatter provided by gridjs.
Refer Docs: https://gridjs.io/docs/examples/html-cells/
My Working code sandbox link: https://codesandbox.io/s/gridjs-hello-world-forked-uvsgom

Kendo Grid UI: Enable custom text copy with multiple row select feature

I am having a kendo grid where the multiple row selection is enabled. With multiple selection functionality, when users try to copy custom text like any value from the column, it enables multiple select features thus users cannot copy custom text.
Below is the sample:
https://dojo.telerik.com/#erpuneet507/ivAfoFup
The issue is, in the above example you can select text from a single cell/ or any partial text from the cell.
If you have multiple selection enabled, then your app has to handle the copy text to clipboard. In doing so, you'll need the clipboard.js library and add a Kendo ContextMenu. Handle the copy text in the ContextMenu select event. Copy Text should pop up on right click.
Try the code below in the Telerik DOJO:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2021.2.616/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2021.2.616/js/kendo.all.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
</head>
<body>
<div id="grid"></div>
<ul id="context-menu">
<li id="copyText">Copy Text</li>
</ul>
<script>
$(document).ready(function() {
$("#grid").kendoGrid({
selectable: "multiple row",
allowCopy: true,
columns: [
{ field: "productName" },
{ field: "category" }
],
dataSource: [
{ productName: "Tea", category: "Beverages" },
{ productName: "Coffee", category: "Beverages" },
{ productName: "Ham", category: "Food" },
{ productName: "Bread", category: "Food" }
]
});
$("#context-menu").kendoContextMenu({
target: "#grid",
filter: "td",
select: function (e) {
var cell = e.target;
var row = $(cell).parent()[0];
var grid = $("#grid").data("kendoGrid");
var itemId = e.item.id;
var cellText = cell.innerText;
if (itemId === 'copyText') {
new Clipboard('#copyText', {
text: function (trigger) {
return cellText;
}
});
};
}
});
});
</script>
</body>
</html>
Here's a revised version of the above. You'll no longer need the clipboard.js. This will show/pop up the text (e.g. coffee) when you right click so that you can copy the 'ffee'.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2021.2.616/styles/kendo.default-v2.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2021.2.616/js/kendo.all.min.js"></script>
</head>
<body>
<div id="grid"></div>
<ul id="context-menu">
<li id="copyText">
<input id="valueText"></input>
<span id="closeValueText" class="k-icon k-i-close"></span>
</li>
</ul>
<script>
$(document).ready(function() {
$("#grid").kendoGrid({
selectable: "multiple row",
allowCopy: true,
columns: [
{ field: "productName" },
{ field: "category" }
],
dataSource: [
{ productName: "Tea", category: "Beverages" },
{ productName: "Coffee", category: "Beverages" },
{ productName: "Ham", category: "Food" },
{ productName: "Bread", category: "Food" }
]
});
var closeContextMenu = false;
var contextMenu = $("#context-menu").kendoContextMenu({
target: "#grid",
filter: "td",
close: function(e) {
if (!closeContextMenu) {
e.preventDefault();
}
},
open: function(e) {
var cell = e.target;
var row = $(cell).parent()[0];
var grid = $("#grid").data("kendoGrid");
var itemId = e.item.id;
var cellText = cell.innerText;
$(e.item).find("#valueText").val(cellText);
closeContextMenu = false;
}
}).data("kendoContextMenu");
$("#closeValueText").on("click", function(e) {
closeContextMenu = true;
contextMenu.close();
});
});
</script>
</body>
</html>

Vue js - multiple components with each a different initial selected value

I'm creating a multiselect in Vue js, but wat i dont understand is how can i get multiple instance of the component with each a different initial selected value (v-model). Every component is getting the same initial value because of the selected data on the parent. Should i also use props here instead of v-model? or should i move the data object from the parent to the component itself?
Wat i want
Component one should have initial select "{ id: "0", text: "One"}" and
Component two should have initial select "{ id: "1", text: "Two"}"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>
<div id="app">
<multi-select v-model="selected" :options='[{ id: "0", text: "One"}, { id: "1", text: "Two"}'></multi-select>
<multi-select v-model="selected" :options='[{ id: "0", text: "One"}, { id: "1", text: "Two"}'></multi-select>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component("multi-select", {
props: ["options", "value"],
template: `
<div>
<div v-for="option in selectedOption">{{ option.text }}</div>
<hr>
<div v-for="option in options">{{ option.text }}</div>
</div>
`,
computed: {
selectedOption() {
return this.value;
}
}
});
new Vue({
el: "#app",
data: {
selected: [{ id: "0", text: "One"}],
}
})
</script>
</body>
</html>
Pass index as props and your child component can use this index to decide the default value.
v-bind:index="0"
v-bind:index="1"
v-model means the selected value, pay attention that you are assigning both multiselects
to the same variable.
a possible solution is creating another variable, lets say selector2 and selector1
and assigning your v-model accordingly.
data: {
selected1: [{ id: "0", text: "One"}],
selected2: [{ id: "1", text: "Two"}],
}
and on assignment
<div id="app">
<multi-select v-model="selected1" :options='[{ id: "0", text: "One"}, { id: "1", text: "Two"}'></multi-select>
<multi-select v-model="selected2" :options='[{ id: "0", text: "One"}, { id: "1", text: "Two"}'></multi-select>
</div>

SlickGrid and copy text from cell

I'm trying to copy the text contents of a cell - I don't need to be able to paste into Excel or anything, I just want the plaintext content. Highlighting text, right clicking, and selecting copy works as expected (so not the same problem as in SlickGrid and Text Selection since I can select text) but highlighting and pressing ctrl+c does not (nothing gets copied to the clipboard).
I tried commenting out the keypress-handling code in slick.grid.js ($canvas.on("keydown", handleKeyDown) and $focusSink.add($focusSink2).on("keydown"), handleKeyDown)) but no change.
Chrome 61 on Windows 10, if it matters.
Reproduce with the Basic use with configuration example, with enableTextSelectionOnCells set to true:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="shortcut icon" type="image/ico" href="favicon.ico" />
<title>SlickGrid example 1: Basic grid</title>
<link rel="stylesheet" href="../slick.grid.css" type="text/css"/>
<link rel="stylesheet" href="../css/smoothness/jquery-ui-1.11.3.custom.css" type="text/css"/>
<link rel="stylesheet" href="examples.css" type="text/css"/>
</head>
<body>
<div id="myGrid" style="width:600px;height:500px;"></div>
<script src="../lib/jquery-1.11.2.min.js"></script>
<script src="../lib/jquery.event.drag-2.3.0.js"></script>
<script src="../slick.core.js"></script>
<script src="../slick.grid.js"></script>
<script>
var grid;
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete"},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
];
var options = {
enableCellNavigation: true,
enableTextSelectionOnCells: true,
enableColumnReorder: false
};
$(function () {
var data = [];
for (var i = 0; i < 500; i++) {
data[i] = {
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
grid = new Slick.Grid("#myGrid", data, columns, options);
})
</script>
</body>
</html>
I was able to get Copy to Clipboard to work using this example:
https://6pac.github.io/SlickGrid/examples/example-excel-compatible-spreadsheet.html
I don't care for paste or much of the other Excel functionality, so I set readOnlyMode on like this:
grid.registerPlugin(new Slick.CellExternalCopyManager({
readOnlyMode : true,
includeHeaderWhenCopying : false,
}));

How to remove dirty flag when editing value in extjs editable grid data?

An extjs editable grid data grid has the following json data named as
data.json
{
"rows" : [ {
"record_id" : 101,
}, {
"record_id" : 102,
"data" : "",
}, {
"record_id" : 103,
"data" : 62,
}, {
"record_id" : "104",
"data" : "62",
} ]
}
While tabbing through the cells, some data cells show up with a dirty flag. Actually, no any data are changed from the point of users. Here is a demo. Of course, there are data missing, or string, or integer type mixing. The case happens in real life, for user don't care about the programming type, etc. The question is how to clean up the dirty flags, since there is no changed data actually, and while submitting, all of the kind of data do not show up in getChanges()? If any data change happends, such as 62 to 625, it should show up a dirty flag; and if reversing back, such as 625 to 62, it should NOT show up a dirty flag, until a "Save" is clicked.
Here is the other files related to the test.
data.html
<!-- <!DOCTYPE html> -->
<html>
<head>
<meta name="google" content="notranslate" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=10, user-scalable=yes">
<title>Gride Data Testing</title>
<script type="text/javascript" src="https://examples.sencha.com/extjs/6.5.1/examples/classic/shared/include-ext.js"></script>
<script type="text/javascript" src="https://examples.sencha.com/extjs/6.5.1/ext-all-debug.js"></script>
<script type="text/javascript" src="https://examples.sencha.com/extjs/6.5.1/examples/classic/shared/options-toolbar.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/extjs/6.2.0/classic/theme-triton/resources/theme-triton-all.css">
<script type="text/javascript" src="data-ext-0.js"></script>
</head>
<body>
<div id="grid-example"></div>
</body>
</html>
data-ext.js
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.util.*',
'Ext.state.*' ]);
Ext.onReady(function() {
var myStore = Ext.create('Ext.data.JsonStore', {
// http://docs.sencha.com/extjs/6.0.2/modern/Ext.grid.column.Column.html
storeId : 'myStore_data',
autoLoad : true,
autoDestroy : true,
proxy : {
type : 'ajax',
url : 'data.json', // the file is defined as the above
reader : {
type : 'json',
keepRawData : true,
rootProperty : 'rows'
}
},
});
var grid = Ext.create('Ext.grid.Panel', {
store : Ext.data.StoreManager.lookup('myStore_data'),
columnLines : true,
border : true,
title : 'Grid Data Testing',
columns : [ {
text : "Record ID",
dataIndex : "record_id",
width : 200,
format : '0',
editor : {
xtype : 'numberfield',
allowBlank : true,
allowNull : true,
}
}, {
text : "Data",
dataIndex : "data",
width : 200,
format : '0',
editor : {
xtype : 'numberfield',
allowBlank : true,
allowNull : true,
}
} ],
selModel : {
selType : 'cellmodel'
},
height : 230,
width : 402,
title : 'Grid Data Testing',
renderTo : 'grid-example',
viewConfig : {
stripeRows : true
},
plugins : {
cellediting : {
clicksToEdit : 1
}
}
});
});
You need to commit your datas after edit, you can do it on edit event of the celleditor plugin like this:
I added a control to commit only if the start and the new value are the same, so the record will not be committed if i change the value in the cell
if the value is null, you need to check also if originalValue and value aren't null
IF YOU DON'T NEED TO COMMIT, you can use this workaround.
the record.set method is not calculated by grid cellediting marker.
cellediting: {
clicksToEdit: 1,
listeners: {
edit: function (editor, context, e) {
if (context.originalValue === context.value ||
(!context.originalValue && !context.value)) {
context.record.set(context.field,context.value);
context.record.set(context.field,context.originalValue);
}
}
}
}
here you can see a working fiddle
The code is updated

Categories