Angular UI Tree - Allow only drag & drop into second level (children nodes) - javascript

I am currently using Angular UI Tree.
My object:
[
{
"id": 1,
"title": "class1",
"students": [
{
"id": 11,
"title": "student1.1",
},
{
"id": 12,
"title": "student1.2"
}
]
},
{
"id": 2,
"title": "class2",
"students": []
},
{
"id": 3,
"title": "class3",
"students": [
{
"id": 31,
"title": "student3.1"
}
]
}
]
What I want to achieve is to allow students to drag & drop inside classes (The classes do not have to be draggable, and students do not have to be dropped into first level (classes) only to a second level (students)).
Is this possible to achieve with Angular UI Tree?

I finally made It like this:
I check in the destination Scope that parent is still a uiTreeNode.
In controller:
$scope.treeOptions = {
accept: function(sourceNodeScope, destNodesScope, destIndex) {
if (destNodesScope.$parent.$type === "uiTreeNode"){
return true;
}else{
return false;
}
}
};
and in view:
<div ui-tree="treeOptions">

Related

Object has many arrays, loop through each and change some value

I have an object that has a whole host of arrays and properties. There is a property called targetProperty which appears in various places of the object.
I have a function where if the user clicks yes, every instance of that property needs to be reassigned to a new value.
The problem is the function that I used for assigning a new value doesn't work in this senario:
reassingPropertyInObj(obj, status) {
if (typeof obj === 'object' && obj !== null) {
obj.targetProperty = status;
for (const key in obj) {
this.handleExpandCollapseClick(obj[key], status);
}
}
},
Does anyone have a solution for this? Also can't use JSON.parse() or anything like that because the properties need to stay reactive for later reassignment if needed by the user.
Below is an example of one object:
{
"id": 16,
"ref_study_id": "3412333",
"title": "SomePersonNameOne",
"capabilities_available": [
{
"id": 75,
"name": "Clinical Data",
},
{
"id": 538,
"name": "RK's Capability",
}
],
"capabilities_impacted": [],
"businessImpact": {
"id": 2,
"name": "Medium"
},
"sites_impacted": [],
"sites_available": []
},
{
"id": 6,
"ref_study_id": "123124",
"title": null,
"capabilities_available": [
{
"id": 37,
"name": "Clinical Site Experience,
},
{
"id": 41,
"name": "Experience",
}
],
"capabilities_impacted": [
{
"id": 37,
"name": "Information Exchange",
"is_study_level": false,
"businessImpact": {
"id": 2,
"name": "Medium"
}
},
{
"id": 39,
"name": "IT/Data Experience",
"is_study_level": false,
"businessImpact": {
"id": 2,
"name": "Medium"
}
},
{
"id": 34,
"name": "Mgmt & Storage",
"is_study_level": false,
"businessImpact": {
"id": 3,
"name": "Minor"
}
}
],
"businessImpact": {
"id": 2,
"name": "Medium"
},
"sites_impacted": [],
"sites_available": []
},
And the property in question is businessImpact. As you can see it appears by itself as a property and inside array (and sometimes those arrays of arrays of their own).
I setup a function like:
arrayOfProperties.forEach((property) => {
obj[property].forEach((o) => {
o.businessImpact = newVal;
});
});
But of course it doesn't go deep enough.

Vue method to list each object in an array of objects leads to errors

This is the dropdown component used to give a list of all grids in all pages. There are multiple pages and grids within those pages.
<v-dropdown
:items="pageGrids"
:item-text="gridNamesAndPages"
return-object
/>
gridNamesAndPages is under methods:
gridNamesAndPages: item => item.name + ' • (Page: ' + item.page_name.name + ')',
This is the method used to assign the empty array summaryGrids to all grids for this project:
getAllPageGrids() {
apiClientGet(
routes["pages.getAllPageGrids"],
null,
response => {
this.pageGrids.push(response.data);
}
);
},
The function in the controller:
public function getAllPageGrids()
{
return Auth::user()->client->grids()->get();
}
SummaryGrids are in this format. There could be multiple grids so whilst this only shows 3 there could be 100:
[
{
"id": 3,
"name": "AS",
"grid_cols": [
{
"id": 16,
"grid_id": 3,
"order": 1,
"header": "Col 1",
}
],
"page_name": {
"name": "Page 1"
}
},
{
"id": 4,
"name": "SF",
"grid_cols": [
{
"id": 21,
"grid_id": 4,
"header": "Name",
},
{
"id": 22,
"grid_id": 4,
"header": "Reference",
}
],
"page_name": {
"name": "Page 1"
}
},
{
"id": 5,
"name": "WE",
"grid_cols": [
{
"id": 24,
"grid_id": 5,
"header": "Name",
}
],
"page_name": {
"name": "Page 2"
}
}
]
However I continue to get this error:
I can't see anything wrong with the way the code is structured. Would anyone know if I've actually written it incorrectly?
(On request I've also included the custom v-dropdown component)
<template>
<v-select
:class="`text-field-${color || 'white'}`"
outlined dense
v-on="$listeners" v-bind="$attrs"
>
<slot>
<!-- -->
</slot>
</v-select>
</template>
<script>
export default {
props: {
color: {
type: String|null,
default: null
}
},
};
</script>

React: trying to check/uncheck checkbox

I'm trying to make an obligatory Todo app to help with my React learning . The behavior I'm going for is multiple Todo lists, where you select a todo name and the list of todo items for that show. Select a different todo name and it's list todo items show, etc (like wunderlist/msft todo). For now it's using static json where each item has a child array.
I'm trying to check/uncheck a checkbox in order to mark the todo as done. My problem is that when a click the checkbox it doesn't update until a click away and then click back. What do I need to do to get it to update immediately?
code sandbox: https://codesandbox.io/s/github/cdubone/todo-react-bootstrap?file=/src/App.js
Here's the relevant code:
The function:
const updateChecked = todo => {
todo.IsChecked = !todo.IsChecked;
};
Properties on the component:
onChange={() => updateChecked(todo)}
isChecked={todo.IsChecked}
The input in the component:
<input
type="checkbox"
id={props.id}
name={props.id}
value={props.title}
checked={props.isChecked}
onChange={props.onChange}
/>
Here's the data -
JSON:
const TodoData = [
{
"Id": 1,
"Title": "Groceries",
"TodoList": [
{
"Id": 1,
"Title": "Apples",
"IsChecked": false
},
{
"Id": 2,
"Title": "Oranges",
"IsChecked": false
},
{
"Id": 3,
"Title": "Bananas",
"IsChecked": true
}
]
},
{
"Id": 2,
"Title": "Daily Tasks",
"TodoList": [{
"Id": 11,
"Title": "Clean Kitchen",
"IsChecked": false
},
{
"Id": 12,
"Title": "Feed Pets",
"IsChecked": false
},
{
"Id": 13,
"Title": "Do Stuff",
"IsChecked": false
}]
},
{
"Id": 3,
"Title": "Hardware Store",
"TodoList": []
},
{
"Id": 4,
"Title": "Costco",
"TodoList": [{
"Id": 21,
"Title": "Diapers",
"IsChecked": false
},
{
"Id": 22,
"Title": "Cat Food",
"IsChecked": false
},
{
"Id": 23,
"Title": "Apples",
"IsChecked": false
},
{
"Id": 24,
"Title": "Bananas",
"IsChecked": false
}]
},
{
"Id": 5,
"Title": "Work",
"TodoList": [
{
"Id": 34,
"Title": "TPS Reports",
"IsChecked": true
}
]
}
]
export default TodoData;
You're mutating state directly rather than using setTodoData to update (a lot of your functions are doing this). Also, you're mapping the the todo items of off ActiveTodoList rather than the todoData which creates a big issue. In react there should only be 1 source of truth, so it would be better to instead store the index of the active list and map "todoData[activeIndex].TodoList.", than to store an instance of the active list itself. Finally, because the data is so nested, you need the list index and the todo item index passed into your update function to reference its location in todoData. Map lets you pass index as a second parameter.
Something along the lines of the below:
todoData[activeIndex].TodoList.map((todo, todoIndex) => {
return (
<div onClick={()=> yourFunction(todo, todoIndex, activeIndex)}> </div>
)
}
yourFunction = (todo, todoIndex, listIndex) => {
let newTodo = {...todo, IsChecked: !todo.IsCheck};
setTodoData((todoData) => [
...todoData.slice(0,listIndex),
{
...todoData[listIndex],
TodoList: [
...todoData[listIndex].Todolist.slice(0,todoIndex)
,newTodo,
...todoData[listIndex].Todolist.slice(todoIndex + 1)
]
},
...todoData.slice(listIndex + 1)
]
}
The goal is not to change things directly, but make copies to send to state. Unfortunately with a nested object it can get confusing very fast.

How to remove items from an array of multidimensional arrays

I need some help on how to remove items from a TreeView (it's a Vue.js project), the TreeView is build based on an element like that:
[
{
"id": 1,
"name": "COMERCIALIZAÇÃO",
"idp": "",
"children": [
{
"id": 5,
"name": "Pasta 1",
"idp": 1,
"children": [
{
"id": 6,
"name": "Pasta 1 2",
"idp": 5,
"children": [
{
"id": 7,
"name": "NO.FT.DRC.01.00.001.pdf",
"file": "pdf",
"idp": 6
},
{
"id": 8,
"name": "PR.FT.DRC.01.00.003.pdf",
"file": "pdf",
"idp": 6
}
]
},
{
"id": 9,
"name": "imprimir p luiza.pdf",
"file": "pdf",
"idp": 5
},
{
"id": 66,
"name": "Pasta 1 3",
"idp": 5,
"children": [
{
"id": 77,
"name": "NO.FT.DRC.01.00.001.pdf",
"file": "pdf",
"idp": 66
},
{
"id": 88,
"name": "PR.FT.DRC.01.00.003.pdf",
"file": "pdf",
"idp": 66
}
]
}
]
},
{
"id": 10,
"name": "Backend.docx",
"file": "pdf",
"idp": 1
},
{
"id": 0,
"name": "DT.DC.RPI.03.03.1235_V2.docx",
"file": "pdf",
"idp": 1
}
]
},
{
"id": 2,
"name": "DISTRIBUIÇÃO",
"idp": "",
"children": [
{
"id": 11,
"name": "Pasta 2",
"idp": 2,
"children": [
{
"id": 12,
"name": "pasta 2 1",
"idp": 11,
"children": [
{
"id": 13,
"name": "script.sql",
"file": "pdf",
"idp": 12
}
]
}
]
}
]
},
{
"id": 3,
"name": "GERAÇÃO",
"idp": "",
"children": [
{
"id": 14,
"name": "Pasta 3",
"idp": 3
}
]
},
{
"id": 4,
"name": "SERVIÇOS",
"idp": "",
"children": [
{
"id": 5,
"name": "teste",
"idp": 4
}
]
}
]
I'm not sure, but I think that the best way to describe that element is: array of mutidimensional arrays, right?
I've created a CodePen to show the closest I got when using recursivity, but surely mine isn't the best solution since it doesn't work on every delete. Take a look at my code: https://codepen.io/luizarusso/pen/zYxLOPb?editors=1010
for (let i = 0; i < items.length; i++) {
if (items[i].id == item.id) {
//se achou o cara que vai ser removido, chama a função de remover
return this.removeItem(i);
} else {
if (items[i].children) {
if (items[i].idp == "") {
this.caminho = [];
}
this.caminho.push(i);
this.delFile(item, items[i].children);
} else {
if (items.length == 1 + i) {
this.caminho.pop();
}
}
}
}
Any ideas? Feel free to optimize my code directly on CodePen if you prefer :)
EDIT: Just to clarify, my problem here is strictly on how to remove an element by the id. When the user clicks on the bin icon I know what element I need to remove, but I don't know how to take it off of the array. Map, Filter and other native JS functions cannot do that to an array of arrays/JSON, so I tought about using recursivity or something else to make it work.
You need to look at objects, not just arrays.
Let me recommend an example library. https://github.com/leezng/vue-json-pretty.
If your question about multidimensional array iteration and process i think you have to ask on javascript and/or algorithm tags.
I hope this answer will help you.
The problem was with where I placed the this.caminho.pop()
I should only do that in the "else" of the condition that compares the id of the current item with the id of the item I'm looking for.
delFile(item, items) {
for (let i = 0; i < items.length; i++) {
if (items[i].id == item.id) {
//if the current item has the same id as the item I'm looking for
//it means I found the guy and I call the function to remove it
return this.removeItem(i);
} else {
//otherwise, I keep on searching
if (items[i].children) {
//if the item on the actual index have children, I'll search among them
if (items[i].idp == "") {
//if the items doesn't have a parent, I clean the "caminho" (path) var. That var traces the route till the item I'm looking for
this.caminho = [];
}
//I push the index to the var that traces the route
this.caminho.push(i);
//I call the function back again, now with the child items
this.delFile(item, items[i].children);
}
if (items.length == 1 + i) {
//if the item's lenght has been completely coursed, I pop the index out of the var that holds the route, because at this point I know the item I'm looking for is not among them
this.caminho.pop()
}
}
}
},
Here is the solution: https://codepen.io/luizarusso/pen/zYxLOPb
Works with treeview with any deepness

Compare two arrays and update with the new values by keeping the existing objects using javascript-Not working for delete operation of objects

This is a follow up question for Compare two arrays and update with the new values by keeping the existing objects using javascript which was ansewered by #Siderite Zackwehdex
Please check this plunker I'm getting the deleted Object in the changedArray1.Is there any option to fix this.Its working fine for other changes like add,update but not for delete.
One feature that I tried to implement is to add an additional object ie., "removedIds":[23] , that holds the deleted id's as an array in each level of objects and identifying them in the evaluation process.. but didn't find the right soultion
Example data:
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"operationalContextId": 1.1,
"valueChainEntityDetails": [
{
"valuChainEntityId": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1",
"activityDetails": [
{
"activityId": 22,
"name": "test 3.1"
},
{ //trying to remove activity id 23
"activityId": 23,
"name": "changed test 23"
}
]
}
]
}
]
}
]
}
]
var changedArray1=[
{
"id": 1,
"name": "test2",
"context": [
{
"operationalContextId": 1.1,
"valueChainEntityDetails": [
{
"valuChainEntityId": 3,
"name": "changed test3",
"context": [
{
"id": 3.1,
"name": "test 3.1",
"removedIds":[23] ,
"activityDetails": [ //activity id 23 is removed in this JSON but reflecting in parentArray1
{
"activityId": 22,
"name": "changed test 3.1"
}
]
}
]
}
]
}
]
}
]

Categories