I wanted to use JavaScript vtree plugin. For this i made a jsonSource. But i only get first child.
I have multiple class and under a campus have multiple class and so is section. My json is like this
[
{
"campus_id": "4",
"campus_name": "Test Campus Name",
"class_id": "11",
"class_name": "STD - VIII",
"section_id": "11",
"section_name": "A"
},
{
"campus_id": "4",
"campus_name": "Test Campus Name",
"class_id": "15",
"class_name": "A' Level",
"section_id": "15",
"section_name": "A"
},
{
"campus_id": "5",
"campus_name": "Dhanmondi",
"class_id": "6",
"class_name": "STD - III",
"section_id": "6",
"section_name": "A"
}
]
Here is how i made the jsonSource for vtree.
<script type="text/javascript">
var json_data = <?php echo $json_data; ?>;
$.each(json_data, function(key,value){
alert(value.section_id);
var jsonSource = {
tree: {
id: "root",
nodes: [{
id: "master",
title: "Select Campus",
hasChildren: true,
nodes: [{
id: value.campus_id,
title: value.campus_name,
hasChildren: true,
nodes: [{
id: value.class_id,
title: value.class_name,
hasChildren: true,
nodes: [{
id: "section_id",
title: value.section_name,
hasChildren: false,
}]
}]
}]
}]
}
};
//initialisation
var tree = Vtree.create({
// mandatory
container: jQuery("#treeContainer"),
// mandatory
dataSource: jsonSource,
// mandatory
plugins:["checkbox"],
// otional. all parents will be open automatically.
initiallyOpen: ["parent_1", "parent_2", "parent_3"],
// optional. default value is true.
displayCheckbox: true,
// list of initially checked nodes
initiallyChecked: ["child_1"],
//optional. default value is 'checkParents'. Checking a node check all his parents automatically. In this case checking child_1 at initialisation checked all his parents.
checkBehaviour: "checkParents",
// optional. default value is 'checked'
checkedClass: "checked",
//optional. default value is 'uncheckChildren'. Unchecking a node uncheck all his children automatically
uncheckBehaviour: "uncheckChildren",
// a list of disabled nodes
disabledCheckboxes: ["parent_3"],
//optional. by default value is 'disableChildren'. in this case disabling parent_3 will disable automatically his children.
disableBehaviour: "disableChildren",
// optional. default value is "disabled". The class applied to disabled nodes.
disabledClass: "disabled",
});
});
</script>
How can i get all the campus and existing classes and sections as child?
Related
I'm using ng2-tree https://angular2-tree.readme.io/v3.2.0/docs/inputs plugin
When i input below json it is showing as undefined
[
{
"value": "helper",
"name": "helper",
"children": []
},
{
"value": "taxi",
"name": "taxi",
"children": []
},
{
"value": "Cake",
"name": "Cake",
"children": [
{
"name": "Chocolate Fudge Cake",
"value": "Chocolate Fudge Cake"
},
{
"name": "Carrot & Walnut Cake",
"value": "Carrot & Walnut Cake"
}
]
}
]
with above json my result is as undefined you can see them in my provided link below
here is the stackblitz link: https://stackblitz.com/edit/angular-ng2-tree-aouyza?file=app/app.component.ts
Please help me thanks in advance!!
Your data structure is wrong. The tree component received as input param a TreeModel and you're having an array of TreeModels at the moment.
Either you adjust your data structure and use a parent TreeModel to wrap your current ones as its children, like following:
tree: TreeModel = {
value: 'Parent Model',
children: [
{
value: 'helper',
name: 'helper',
children: [],
},
{
value: 'taxi',
name: 'taxi',
children: [],
},
{
value: 'Cake',
name: 'Cake',
children: [
{
name: 'Chocolate Fudge Cake',
value: 'Chocolate Fudge Cake',
},
{
name: 'Carrot & Walnut Cake',
value: 'Carrot & Walnut Cake',
},
],
}
]
};
Or you iterate over the array in the HTML and use multiple tree components. That would look like following:
<tree [tree]="t" *ngFor="let t of tree"></tree>
For more information see the Github page of ng2-tree ;)
Update:
You still need to adjust the data model the way I suggested but you can hide the empty root node. To do so, you need to do following:
HTML
<tree [tree]="tree" [settings]="{ rootIsVisible: false }"></tree>
Due to this setting a class rootless is applied which hides the empyt root node but only if you've added node_modules/ng2-tree/styles.css to your angular.json or you've added a custom implementation for that class.
You can find the settings doc here.
Below is the JSON, I am using to generate following UI:
{
"Text" : "1. Parent group"
"Logic" : "all of the following",
"Id":"1" //some unique id
"children": [
{
"Text' : "1.1 Level Child group"
"Logic' : "1 or more of the following",
"Id':"1.1" //some unique id,
"children" : [
{
"Text' : "1.1.1 Level Child group"
"Logic' : "all of the following",
"Id':"1.1.1" //some unique id,
"children": [
{
"Text' : "1.1.1.1 Level Child"
"Id':"1.1.1.1" //some unique id,
},
{
"Text' : "1.1.1.2 Level Child"
"Id':"1.1.1.2" //some unique id,
"Logic" : "one or more of the following",
"children" : [
{
"Text": "1.1.1.2.1 Level Child",
"Id": "1.1.1.2.1"
},
{
"Text": "1.1.1.2.2 Level Child",
"Id": "1.1.1.2.2"
},
]
}
]
},
{
"Text' : "1.1.2 Level Child group"
"Id':"1.1.2" //some unique id,
},
{
"Text' : "1.1.3 Level Child group"
"Id':"1.1.3" //some unique id,
},
{
"Text' : "1.1.4 Level Child group"
"Logic' : "one or more of the following",
"Id':"1.1.4" //some unique id,
"children": [
{
"Text' : "1.1.4.1 Level Child"
"Id':"1.1.4.1" //some unique id,
},
{
"Text' : "1.1.4.2 Level Child"
"Id':"1.1.4.2" //some unique id,
}
]
},
{
"Text' : "1.1.5 Level Child group"
"Logic' : "all of the following",
"Id':"1.1.5" //some unique id,
"children": [
{
"Text' : "1.1.5.1 Level Child"
"Id':"1.1.5.1" //some unique id,
},
{
"Text' : "1.1.5.2 Level Child"
"Id':"1.1.5.2" //some unique id,
}
]
}
]
},
{
"Text" : "1.2 Level Child"
"Id":"1.2" //some unique id
}
]
}
1. Parent group (all of the following)
1.1 Level Child group (1 or more )
1.1.1 Level Child group (all of the following)
1.1.1.1 Level Child // selectable
1.1.1.2 Level Child // selectable
1.1.2 Level Child // selectable
1.1.3 Level Child // selectable
1.1.4 Level Child group (one or more of the following)
1.1.4.1 Level Child // selectable
1.1.4.2 Level Child // selectable
1.1.5 Level Child group (all of the following)
1.1.5.1 Level Child // selectable
1.1.5.2 Level Child // selectable
1.2 Level Child // selectable
Node working logic:
only nodes with no children can be selected by the user.
Node is implicitly selected if the Logic is "all of the following" if and only if all its nested children are selected
Node is implicitly selected if the logic is "n or more of the following" if only if its "n" nested children are selected
Scenario: If the user selects 1.1.2(it implicitly satisfies 1.1) and 1.2 then "1. parent group" is "Met", so it is selected(makes the whole group met);
Scenario: If the user selects 1.1.1.1, the user has to select 1.1.1.2 so that 1.1.1 is "Met" and selecting 1.2, will make the whole group as "Met".
Actual need is to find the optimal ids when "parent group is not met":
If the selecting any nodes and the top most parent group is still not "met".
Then On a button click, I need to find and return the optimal node ids
whose presence would have made the "parent group" to be "Met".
NOTE : when finding the optimal node ids we should importance to child groups if any of its children are selected.
For eg:
If only 1.2 is selected by the user, the fastest way to make the
"parent group" to met is to select 1.1.2. But if 1.1.1 has any children
selected, then I should give precedence to 1.1.1 node, as result I
need to return following ids: [
1.1.1.2, 1.1.1, 1.1 ]
Not sure what type of algorithm, I should be using to solve this problem.
Here a short approach by having a look to the constraints, which are now in the data set metioned with q: 'some' or q: 'every'.
function select(node, selected) {
function iter(node) {
if (!node.children) return [node.Id];
var temp = node.children.map(iter);
if (node.q === 'every') return [...temp.flat(), node.Id];
var filtered = temp.filter(a => a.some(v => selected.includes(v)));
if (filtered.length) return [...filtered.flat(), node.Id];
return [...temp.reduce((a, b) => b.length < a.length ? b : a), node.Id];
}
return iter(node).filter(v => !selected.includes(v));
}
var data = { q: 'every', Text: "1. Parent group", Logic: "all of the following", Id: "1", children: [{ q: 'some', Text: "1.1 Level Child group", Logic: "1 or more of the following", Id: "1.1", children: [{ q: 'every', Text: "1.1.1 Level Child group", Logic: "all of the following", Id: "1.1.1", children: [{ Text: "1.1.1.1 Level Child", Id: "1.1.1.1" }, { Text: "1.1.1.2 Level Child", Id: "1.1.1.2" }] }, { Text: "1.1.2 Level Child group", Id: "1.1.2" }, { Text: "1.1.3 Level Child group", Id: "1.1.3" }, { q: 'some', Text: "1.1.4 Level Child group", Logic: "one or more of the following", Id: "1.1.4", children: [{ Text: "1.1.4.1 Level Child", Id: "1.1.4.1" }, { Text: "1.1.4.2 Level Child", Id: "1.1.4.2" }] }, { q: 'every', Text: "1.1.5 Level Child group", Logic: "all of the following", Id: "1.1.5", children: [{ Text: "1.1.5.1 Level Child", Id: "1.1.5.1" }, { Text: "1.1.5.2 Level Child", Id: "1.1.5.1" }] }] }, { Text: "1.2 Level Child", Id: "1.2" }] };
console.log(select(data, ["1.2"]));
console.log(select(data, ["1.2", "1.1.1.1"]));
console.log(select(data, ["1.1.1.1"]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have a Kendo grid where I'm trying to add a delete feature. My datasource looks like:
var datasource = new kendo.data.DataSource({
transport: {
read: {
url: Router.action("Admin", "GetScansForMailItem", { mailItemIdnt: detailinit.data.MailItemIdnt }),
dataType: "json"
},
destroy: {
url: Router.action("Admin", "DeleteScan"),
type: "post"
}
},
model: {
id: "ScanIdnt",
fields: {
ScanIdnt: {editable: false, nullable: false}
}
},
pageSize: 5
});
I added the model part because this answer, however it made no difference.
The actual grid looks like:
.kendoGrid({
dataSource: datasource
scrollable: false,
sortable: true,
pageable: true,
editable: "inline",
columns: [{
field: "ScanIdnt",
title: "Scan ID"
}, {
field: "CreatedDate",
title: "Created",
template: "#= kendo.parseDate(CreatedDate, 'yyyy/MM/dd') #"
}, {
field: "ScanDocumentRelativePath",
title: "File Path",
template: "<a href='/CAMP/Admin/Download?scanIdnt=#= ScanIdnt #'>#= ScanDocumentRelativePath.substring(1) #</a>"
}, {
field: "ScanUserIdnt",
title: "Scanned By"
},{
command: "destroy",
title: ""
}]
});
Strangely, clicking the delete button removes the from the gird on the UI, but there is absolutely no Ajax call is made the the destroy URL. I can't seem to figure out why. Any ideas?
EDIT I'd like to point out that this grid is in fact a nested grid inside of another grid (like here) I discovered that the parent grid handles actually makes a call, but to the wrong function. For some reason, it clicking delete on a to level item calls the read function of the nested grid, however, the nested grids do nothing
Figured it out (sorta). While I think there were many issues with my code and the grid, It seems that when it came down to it, Kendo didn't like how I had my data.
In the Kendo docs related to hierarchical grids, the data for the child grid is stored in a field of the data for the parent. For example, given the following JSON:
"ParentItems": [
{
"Id": 12345 ,
"Name": "Test1",
"ChildItems": [
{"Id": 1, "Name": "Test"},
{"Id": 2, "Name": "Test"}
]
},
{
"Id": 12346 ,
"Name": "Test2",
"ChildItems": [
{"Id": 1, "Name": "Test"},
{"Id": 2, "Name": "Test"}
]
}
]
In the parent grid, each ParentItem would display it's respective ChildItems in the child grid.
On the other hand, I was pulling both data sets separately. Basically, I pulled the ParentItems like:
"ParentItems": [
{
"Id": 12345,
"Name" : "Test1"
},
{
"Id": 12346,
"Name" : "Test2"
}
]
And then made a second request to pull the child items, based on the parent's id.
"ChildItems": [
{"Id": 1, "Name": "Test", "ParentId": "12345"},
{"Id": 2, "Name": "Test", "ParentId": "12345"}
]
I was able to modify the server side code to serve the data like in the very first example and managed to get things working. The specific document that helped me out can be found here
I'm giving following data input to select2
data = [{
"id": "all",
"text": "All",
"children": [{
"id": "item1",
"text": "item1"
}, {
"id": "item2",
"text": "item2"
}]
}];
and I'm initialising select2 as:
$(parent).select2({"data":data});
Now to select the value "item1", I did
$(parent).select2("val",["item1"]);
However instead of value "item1" value "all" is getting selected. How to select value item1?
To set the selected value using select2 you should use:
$(parent).val("item1").trigger("change");
From the release notes:
You should directly call .val on the underlying element instead. If you needed the second parameter (triggerChange), you should also
call .trigger("change") on the element.
$("select").val("1"); // instead of $("select").select2("val", "1");
JSFiddle where item1 is selected.
JS:
var data = [{
id: 'all',
text: 'All',
children: [{
id: 'item1',
text: 'item1'
}, {
id: 'item2',
text: 'item2'
}]
}];
$('.js-example-data-array').select2({data:data});
$('.js-example-data-array').select2('val',['item1']);
HTML:
<select class="js-example-data-array">
</select>
I tried to make this demo to show you that it works. The demo, uses the select tag as a selector for an empty and existing select element. Indeed, I don't know what are you meaning by parent:
<select>
</select>
<script>
data = [{
"id": "all",
"text": "All",
"children": [{
"id": "item1",
"text": "item1"
}, {
"id": "item2",
"text": "item2"
}]
}];
$('select').select2({
"data": data
});
$('select').select2("val", ["item2"]);
</script>
I'm not sure if you mean that the value "All" gets selected at start or if you want to select "item1" by code and it doesn't work. I find it strange that "All" gets selected as value since it should be treated as a category, even by adding
$(".select2-text").select2("val",["item1"]);
it won't select "All" for me. If i add
$(".select2-text").select2("val",["item2"]);
It will select "item2" for me (which means the method to select the item works, though it's not the best way, as stated in Lelio Faieta's Answer)
if i add
$(".select2-text").select2("val",["all"]);
it won't select "All" for me, it will just show me a blank select. So I think there must be an issue with your code because in a clean page there seems to be no way to select "All"
Can you show us the whole code, including the html of your page (at least the part relevant to the select). I have tried this (see plunker here: http://plnkr.co/edit/m6pFUt?p=preview )
<script>
$(document).ready(function() {
data = [{
"id": "all",
"text": "All",
"children": [{
"id": "item1",
"text": "item1"
}, {
"id": "item2",
"text": "item2"
}]
}];
$(".select2-text").select2({
"data": data
});
});
</script>
<select class="select2-text"></select>
And it starts with item1 selected, while "All" is treated as a category. So maybe it's just because something is wrong in your code/HTML.
What version of Select2 are you using? i'm using 2-4.0.0
bit of background: when a user clicks an element, it loads a form retrieved by an ajax call. I save a copy of the json in the controller, and when they change a value, it is to update the local json.
Let's say the json is something like this:
{
name: "questions!",
id: "0",
questions: [{
id: "1",
text: "ninjas or pirates?",
type: "radio",
answers: [{
id: "1",
text: "ninjas"
} , {
id: "2",
text: "pirates"
}],
}, {
id: "3",
text: "why?",
type: "text"
answers: []
}]
}
the element returned is a jquery-ized version of the input that was selected.
While I could iterate through each field and check, I can't help but feel like there is a better way to do it and reference it more directly. How would this be done?