How to update jstree node values without reload - jstree

I have a jstree that I created with the following code:
$('#mytree').jstree({"core": { "data" : value
, "themes" : { "dots": false
, "icons": false }
}
}
);
I can rebuild it with new data by this code:
$('#mytree').jstree(true).settings.core.data = new_data;
$('#mytree').jstree(true).refresh();
but it can be expensive when you have a lot of nodes. What I would like to achieve is that I would like update the value of the elements (i.e. the node.text part) without rebuilding the whole tree. I get the new values via websocket in one message (the complete JSON string that will be the new_data) but the structure is not changing. How can I do that? Thank you!

What you need is not refresh() but redraw() thus the code is
$('#mytree').jstree(true).settings.core.data = new_data;
$('#mytree').jstree(true).redraw(true);
You can find the functions in the jstree API.
As per zmirc suggestion, in v3.1 use:
$('#mytree').jstree(true).settings.core.data = new_data;
$('#mytree').jstree(true).refresh();

for deleting the node and reload tree
$('#mytree').jstree(true).refresh();
for those who need to redraw without restart the tree use
jQuery('#data').jstree(true).refresh(true);

worked for me: $('#structureRows').jstree("destroy").empty();
function CreateStructureTree(jsonData)
{
$('#structureRows').jstree("destroy").empty();
$('#structureRows').jstree
({
'core' : {
'data':
[
jsonData,
{
'id' : 'node_2',
'text' : 'Root node with options',
'state' : { 'opened' : true, 'selected' : true },
'children' : [ { 'text' : 'Child 1' }, 'Child 2']
}
]
}
});
}

You can refresh node by this
$('#treeView').jstree(true).refresh_node("node_id_here")

$('#mytree').jstree(true).refresh();
is working, but in my case it causes thread leak.
every refresh adds one more thread

I load data via an url, so my refresh part looks like:
$('#groupTree').jstree(true).settings.core.data.url = get_group_url();

$('#YourJSTREE').jstree("destroy").empty();
Set new data
$('#YourJSTREE').jstree(true).refresh();

Related

validating forms $refs returning undefined vuejs

I am trying to validate my form but when I try to call the validation method it's returning the value undefined instead of Boolean. Can anyone help me fix the problem ? This below code is the one I am using to validate. By the way I am trying validate it in a child component. Which is only gonna render and show a dialogue when clicking a button.
computed:{
employeeFormValidation(){
this.$refs.employeeForm.validate((valid)=>{
return valid ? true : false
},
employeeAddressValidation(){
this.$refs.employeeAddress.validate((valid)=>{
return valid ? true : false
})
},
employeeDetailsValidation(){
this.$refs.employeeDetails.validate((valid)=>{
return valid ? true : false
})
},
bankDetailsValidation(){
this.$refs.bankDetails.validate((valid)=>{
return valid ? true : false
})
},
Vue is not design as everything is reactive, the docs says "$refs is also non-reactive"
One way to do is use methods instead of computed, But the downside is that this will be re-called even if the dependency has not changed.
However, according to Vue's design philosophy, it should use less refs, accept the values emited by the component, and store them in data.
<your-child-components
#validate="(ok) => (valiateEmployeeDetails = ok)"
>
<your-child-components
#validate="(ok) => (valiateEmployeeAddress = ok)"
>
{
data(){
return {
valiateEmployeeDetails: false,
valiateEmployeeAddress: false,
}
}
}
React has a doucment about "when to use refs", it's the same in Vue.

How can I test the content in ag-grid using testing-library?

I am trying to write a few simple tests that the headers and data I want to render are showing up as expected. I created a repo - https://github.com/olore/ag-grid-testing-library to reproduce. The table looks as I would expect when opened in a browser.
<AgGridReact
columnDefs={ /* First 2 always findable, others never */
[
{ field: "make" },
{ field: "model" },
{ field: "price" },
{ field: "color" },
]}
rowData={
[{
make: "Toyota",
model: "Celica",
price: "35000",
color: "blue"
}]
}
pagination={true}></AgGridReact>
And the tests
test('renders all the headers', async () => {
const { getByText } = render(<GridExample />);
expect(getByText("Make")).toBeInTheDocument(); // PASS
expect(getByText("Model")).toBeInTheDocument(); // PASS
expect(getByText("Price")).toBeInTheDocument(); // FAIL
expect(getByText("Color")).toBeInTheDocument(); // FAIL
});
Locally, the first 2 column headers and data are accessible, but none of the other columns are rendered, as I can see in the output of testing-library. I am using --env=jsdom-fourteen as recommended by other posts.
Strangely enough, no headers or data are rendered for the tests when in the codesandbox for this repo, as with local, the browser looks correct.
https://codesandbox.io/s/gallant-framework-e54c7. I then tried waiting for gridReady
https://codesandbox.io/s/intelligent-minsky-wl17y, but it didn't make a difference.
EDIT: Also tried directly calling a function in onGridReady, same problem (first 2 columns pass, second 2 fail)
test('renders all the headers', async (done) => {
let page;
const onReady = () => {
expect(page.getByText("Make")).toBeInTheDocument(); // PASS
expect(page.getByText("Model")).toBeInTheDocument(); // PASS
expect(page.getByText("Price")).toBeInTheDocument(); // FAIL
expect(page.getByText("Color")).toBeInTheDocument(); // FAIL
done();
}
page = render(<GridExample ready={onReady}/>);
});
ag-grid uses Column Virtualisation, so it seems the solution here is to disable it via the suppressColumnVirtualisation attribute on the <AgGridReact> element.
<AgGridReact
suppressColumnVirtualisation={true}
...
Boom! All the tests pass!
In reality, it's probably ideal to only suppress this during testing:
suppressColumnVirtualisation={process.env.NODE_ENV === "test"}
An addition to #olore's answer.
If you use server side data source, make sure
Your mock server responds with expected data, not error.
You use asynchronous selector in testing library, at least for the first cell of the row.
expect(await findByText('Price')).toBeInTheDocument();

jstree with ajax search and massload plugin

I'm trying to get the massload plugin to work with my jstree configuration. The nodes are built as Country->City->Site->Product->License. When the tree is loaded initially, only the top level nodes are loaded (in my case Countries). When a user expands a node, the children are loaded using ajax. I have a search box that searches in the tree, this works, but it only matches on nodes that are already loaded. I would like to this to work on all site level nodes, loaded or not.
The search ajax call to returns a list of site ids, which is passed to the massload plugin. It calls the LazyLoad method with the correct ids. What I'm can't figure out is what to return in response to the massload call. According to this, it should take the form of
{
"id1" : { "id" : node_id_of_child1, "text" : "child2", "id" : node_id_of_child2, "text" : "child2" },
"id2" : { ... node data ...}
}
Where id1 and id2 are matching node id's from the search.
But when I do that, the nodes aren't added to the tree and the search term only matches on nodes already loaded.
This is my jstree configuration
$('#tree').jstree({
core: {
data: {
url: '#Url.Action("Nodes", "Home")',
data: function (node) {
if (node.id === '#')
return {
nodeType: 'root'
};
else
return {
nodeType: node.data.type,
nodeValue: node.data.value
};
},
type: 'POST'
}
},
plugins: ["massload", "search"],
search: {
"show_only_matches": true,
ajax: {
url: '#Url.Action("Search", "Sites")',
type: 'POST'
}
},
massload: {
url: '#Url.Action("LazyLoader", "Home")',
data: function (nodes) {
return { "ids": nodes.join(",") };
},
type: 'POST'
},
themes: {
"theme": "default",
"dots": false,
icons: true
}
});
Questions:
- Is the response format from the massload ajax call correct?
- What is the massload plugin's action based on this response? Should it try to load the nodes in the response in the same way (i.e. using the same ajax call) the nodes are loaded when a user requests them?

Hierarchial JSON model and UI5

I am creating a demo application with JSON data and UI5. The idea (in a nutshell) is provide various information views for a selected item. I am using IconTabBar control. I have created an example scenario so (hopefully) I can explain the problem more clearly.
1.IconTabBar's first tab has list of employees and user can select one by selecting a radio button on the left
2.This takes the user to the next tab that displays say, sales view. The user can click on any tab and move to the respective view.
3.User can modify the information in any view. If the users forgets or ignores to Save the data, the tab color is set to Red.
4.User can Save the data.
5.Some of the views have information in master detail format.
The problem(s) I am facing are:-
1.How to filter the model data based on the item selected in the table?
2.How to update the filtered data and set back to model?
3.I also would like to know whether the data is structured correctly
I am using following code to update the binding path after company is selected. The GREP function is not returning correct values for proposals. It returns ONLY 1 proposal for E001 whereas it should return 2. It doesn't work properly for orders either. I am not sure whether the data is structured correctly.
var oModel_Data = oJSONDataModel.getData();
var oView_Data = oViewDataModel.getData();
var aModelData = oModel_Data[sSelected_Key];
var aViewData = oView_Data[sSelected_Key];
aViewData = jQuery.grep(aModelData, function(data, index) {
return data.id === sSelected_id
})[0];
oView_Data[sSelected_Key]=aViewData;
oViewDataModel.setData(oView_Data);
oViewDataModel.refresh(true);
I am using following code to check whether user has changed data.
var oView_Data = oViewDataModel.getData();
var oModel_Data = oJSONDataModel.getData();
var aViewData = oView_Data[in_sKey];
var aModelData = oModel_Data[in_sKey];
aModelData.forEach(function(item, index, array) {
var valueView = aViewData;
if (item.id === sSelected_id){
//The code here need to consider complex(nested) data types
//Thus it should check type of not only valueView and item
//but also their each and every child elements
/*---------Temporary Solution---------------------*/
var sViewValue = JSON.stringify(valueView);
var sItem = JSON.stringify(item);
var bSameData = sViewValue === sItem;
if (bSameData==true){
flag_data_changed=false;
}else{
return flag_data_changed=true;
}
}
});
My json model is as below.
{
"employees": [
{"id":"E0001" ,
"name":"Alec Stewert"
},
{"id":"E0002" ,
"name":"Debra Manning"
}
],
"sales": [
{"id":"E0001" ,
"sale_q1":"10000",
"sale_q2":"3000",
"sale_q3":"8000",
"sale_q4":"2000"
},
{"id":"E0002" ,
"sale_q1":"8000",
"sale_q2":"3000",
"sale_q3":"7000",
"sale_q4":"5000"
}
],
"proposal":[
{"id":"E0001",
"fi_q":"Q2",
"value":"12000",
"customer":"6000"
},
{ "id":"E0001",
"fi_q":"Q2",
"value":"8000",
"customer":"2300"
}
],
"key_orders": [
{"id":"E0001",
"order_hdr":
[
{"id":"O0001",
"fi_q":"Q1",
"value":"2000",
"customer":"2000"
},
{"id":"O0002",
"fi_q":"Q1",
"value":"2000",
"customer":"2000"
}
],
"order_dtl":[
{
"id":"O0001",
"itm":"Item X",
"Qty":"100",
"rate":"20"
}
]
},
{"id":"E0002",
"order_hdr":
[
{"id":"O0011",
"fi_q":"Q1",
"value":"2000",
"customer":"5000"
},
{"id":"O0012",
"fi_q":"Q1",
"value":"1000",
"customer":"5000"
}
],
"order_dtl":[
{
"id":"O00011",
"itm":"Item Z",
"Qty":"200",
"rate":"10"
}
]
}
]
}
I have investigated online and in SAP Help but failed to understand what needs to be done. Any help is appreciated.
1.How to filter the model data based on the item selected in the table?
If you prepare the JSONModel you can use the Filter
2.How to update the filtered data and set back to model?
If you bind the table to the JSONModel, by default the JSNOModel is 2 way binding so any edited data will be in the JSONModel
3.I also would like to know whether the data is structured correctly
Go through the Example of the Table So you will get an idea of the Model and binding model to the Table

What am I doing wrong when manipulating data in Meteor/MongoDB?

I have this helper
myClub: function(){
var currentUserId = Meteor.userId();
var user = Meteor.users.findOne({_id: currentUserId});
return user;
}
I want it to return user.role
Here is my user in MongoDB
{
"_id" : "RdirmrLG3t8qBk4js",
"createdAt" : ISODate("2016-04-17T19:40:56.877Z"),
"services" : {
"password" : {
"bcrypt" : "$2a$10$cPe92XR9DT238bH/RanYEu.J6K2ImvAEbWOcVq6j9luI0BH08Qdly"
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2016-04-17T19:51:49.474Z"),
"hashedToken" : "uVKUj/7JEkkOuizXhjl212Z38E47HXCex+D4zRikQ1k="
}
]
}
},
"username" : "worker",
"role" : "worker",
"club" : "hzSKAJfPXo7hSpTYS"
}
The code above works just fine. So it finds the current user and outputs info about it. But when I change user to user.role I get the following errormessage.
TypeError: Cannot read property 'role' of undefined
at Object.myClub
How can it be undefined? Is my syntax incorrect?
Template helpers are reactive, which means they update themselves as the app state changes or new data appears. In your case, the helper is called immediately when the template is rendered and before the Meteor.users collection is filled. Therefore, the .findOne() method returns undefined. It will be corrected in the second pass after new data arrives.
The simple fix here is to check whether the data is present inside the helper:
myClub: function(){
var currenUserId = Meteor.userId();
var user = Meteor.users.findOne({_id: currenUserId});
if(!user) return 'NO DATA';
return user.role;
},
In real life you'll probably want to wait for the basic data to be loaded before you render the template. That is usually done on the controller level.
Try:
myClub: function(){
return Meteor.user() && Meteor.user().role;
}
This is shorthand for return the role if there's a user.
As far as the role field not showing up, make sure that you are publishing that key from the server and subscribing to it. For example:
Meteor.publish('me',function(){
return Meteor.users.find(this.userId,{fields: {role: 1, username: 1, profile: 1, emails: 1}});
});
And on the client:
var me = Meteor.subscribe('me');
if ( me.ready() ) console.log("Ta-da! The role is: "+Meteor.user().role);
make sure that you subscribed to all data you need.
By the way, you can try following:
role: function(){ return (Meteor.user() || {}).role; }
Cheers