DEMO
createBtns function create as many buttons as data array is long.
What I want to do is to delete (from DOM) single button when we click on it. The problem is all buttons has the same class, they are all the same, except text value inside of each. There should be a way to get to know which button has been clicked and delete this and only one, but I don't know it.
There is btnClick function which should do it (it alerts for now).
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click(() => btnClick());
outer.append(btn);
}
}
var btnClick = () => {
alert("test");
}
createBtns();
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
e.currentTarget.remove()
}
createBtns();
I assume $ is JQuery?
edit: (from comments)
And if I'd like to also update data array, how would it look like? I mean delete the object from data when button disappears
On this I can think of two kind of approach, the first is to embed the data into the button
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
btn[0].data = data[i];
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
var index = data.indexOf(e.currentTarget.data);
data = data.slice(0,index).concat(data.slice(index+1,data.length));
e.currentTarget.remove()
}
createBtns();
the second approach is just delete the data and re-render the whole thing
var data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
btn[0].data = data[i];
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
var index = data.indexOf(e.currentTarget.data);
data = data.slice(0,index).concat(data.slice(index+1,data.length));
outer[0].innerHTML = "";
createBtns();
}
createBtns();
If you use const and let (block scoped rather than function scoped), you can simply reference the created btn again inside the handler and .remove() it in the closure:
btn.click(() => btn.remove());
const data = [
{name: "Date", value: "12/31/2018", type: "visible"},
{name: "Car", value: "Ford", type: "visible"},
{name: "Country", value: "Russia", type: "visible"},
{name: "Age", value: "20", type: "visible"},
];
const outer = $(".outerPanel");
const createBtns = () => {
for (let i = 0; i < data.length; i++) {
const btn = $('<div class="btn"></div>');
const name = data[i].name;
const value = data[i].value;
btn.html(name + ": " + value);
btn.click(() => btn.remove());
outer.append(btn);
}
}
createBtns();
.outerPanel {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.btn {
width: 20%;
height: 40px;
border: 2px solid red;
text-align: center;
vertical-align: center;
cursor: pointer;
}
.btn:hover {
background: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outerPanel"></div>
(without const and let, you'd have to use something like this instead - still works, but it's a lot uglier)
You can do this like below:
var btnClick = (e) => {
// get index of clicked button relative to parent element
var index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
// remove data entry in array
data.splice(index, 1);
// remove the clicked button
e.target.parentNode.removeChild(e.target);
}
Updated version of your demo:
var data = [{
name: "Date",
value: "12/31/2018",
type: "visible"
},
{
name: "Car",
value: "Ford",
type: "visible"
},
{
name: "Country",
value: "Russia",
type: "visible"
},
{
name: "Age",
value: "20",
type: "visible"
},
];
var outer = $(".outerPanel");
var createBtns = () => {
for (var i = 0; i < data.length; i++) {
var btn = $('<div class="btn"></div>');
var name = data[i].name;
var value = data[i].value;
btn.html(name + ": " + value);
btn.click((e) => btnClick(e));
outer.append(btn);
}
}
var btnClick = (e) => {
// get index of clicked button relative to parent element
var index = Array.prototype.indexOf.call(e.target.parentNode.children, e.target);
// remove data entry in array
data.splice(index, 1);
// refresh displayed text
refreshText();
// remove the clicked button
e.target.parentNode.removeChild(e.target);
}
var refreshText = () => {
document.getElementById("dataText").innerHTML = JSON.stringify(data);
}
createBtns();
refreshText();
.outerPanel {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.btn {
width: 20%;
height: 40px;
border: 2px solid red;
text-align: center;
vertical-align: center;
cursor: pointer;
}
.btn:hover {
background: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outerPanel"></div>
<h3>Data array contents</h1>
<p id="dataText"></p>
Update
removing the btn from DOM instead of CSS change
Solution
You can add an event listener to the button when u create it inside the for loop.
Example code here:
var data = [{
name: "Date",
value: "12/31/2018",
type: "button"
},
{
name: "Car",
value: "Ford",
type: "button"
},
{
name: "Country",
value: "Russia",
type: "button"
},
{
name: "Age",
value: "20",
type: "button"
},
];
const createBtns = () => {
for (var i = 0; i < data.length; i++) {
let btn = document.createElement('input');
btn.setAttribute('class', 'btn');
btn.setAttribute('value', data[i].value);
btn.setAttribute('type', data[i].type);
btn.addEventListener('click', () => {
document.body.removeChild(btn)
});
document.body.appendChild(btn);
}
}
createBtns();
You can try add an event to the button, like this :
function addHideEvent(element) {
for(i=0;i<element.length;i++) {
element[i].onclick = function(e) {
this.remove()
}
}
}
addHideEvent(document.getElementsByClassName("btn"))
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
<button class="btn"> CLICK HERE </button> </br>
Related
i am working on react-flow, and my task is to transform the following data => `
`const configObj = {
name: "Dataset",
nodeChild: {
type: "schema",
nodeConfiguration: {
sid1: {
name: "Schema 1",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did1: {
name: "Dashboard 1"
}
}
}
},
sid2: {
name: "Schema 2",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did2: {
name: "Dashboard s1",
},
did3: {
name: "Dashboard 3"
}
}
}
}
}
}
}` to this ->
const elements = [
{
id: '1',
type: 'input', // input node
data: { label: 'Input Node' },
position: { x: 250, y: 25 },
},
// default node
{
id: '2',
// you can also pass a React component as a label
data: { label: <div>Default Node</div> },
position: { x: 100, y: 125 },
},
{
id: '3',
type: 'output', // output node
data: { label: 'Output Node' },
position: { x: 250, y: 250 },
},
// animated edge
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3' },
];
`
not exactly but according to data1 so i prepare a code for it and it is working well in node environment but the moment i try it on react it shows some errorenter image description here here is my code
const configObj = {
name: "Dataset",
onClick: true,
nodeChild: {
type: "schema",
nodeConfiguration: {
sid1: {
name: "Schema 1",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did1: {
name: "Dashboard 1"
}
}
}
},
sid2: {
name: "Schema 2",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did2: {
name: "Dashboard s1",
nodeChild: {
type: "ritik",
nodeConfiguration: {
ri1: {
name: "Ritik",
}
}
}
},
did3: {
name: "Dashboard 3"
}
}
}
}
}
},
}
let count =1;
let dataConfig = []
const recursion = (obj, level,type) => {
let objData = {}
for(let j in obj){
if(j !== 'nodeChild' && j !== 'nodeParent'){
if(j === 'name'){
objData= {
...objData,
label: obj[j]
}
}else {
objData= {
...objData,
[j]: obj[j]
}
}
}
}
let idd = count
dataConfig = [...dataConfig, {id: count, data: objData, type, level, parentID}]
count++;
if('nodeChild' in obj){
const {nodeConfiguration, type} = obj.nodeChild
for(let val in nodeConfiguration){
recursion(nodeConfiguration[val], level+1, type, parentID = idd)
}
}
if('nodeParent' in obj){
const {nodeConfiguration, type} = obj.nodeParent
for(let val in nodeConfiguration){
recursion(nodeConfiguration[val], level-1, type)
}
}
}
recursion(configObj, level=0, type='root', parentID=1)
let edges = []
for(let i=1; i<dataConfig.length; i++){
let e = {
id: `e${dataConfig[i].id}-${dataConfig[i].parentID}`,
source: `${dataConfig[i].parentID}`, target: `${dataConfig[i].id}`, animated: true
}
edges = [
...edges,
e
]
}
let finalDataSet = []
let x=650, y=25;
let flag = false;
for(let i in dataConfig){
let element = {}
for(let key in dataConfig[i]){
if(key !== 'parentID'){
if(key === 'type'){
let k = dataConfig[i][key]
if(k === 'schema' || k === 'root'){
element = {
...element,
[key]: 'input'
}
}else {
element = {
...element,
[key]: 'output'
}
}
}else {
element = {
...element,
[key]: dataConfig[i][key]
}
}
}
}
element = {
...element,
position: { x, y }
}
// console.log(i)
finalDataSet = [
...finalDataSet,
element
]
y += 75;
if(!flag){
x = 25;
}
x = flag ? x+155 : x
flag = true
}
for(let i =0; i<edges.length; i++){
finalDataSet = [
...finalDataSet,
edges[i]
]
}
const DataSET = finalDataSet
export default DataSET
this code is perfectly working on local nodejs but the same code pops errors on react.js can any one help me on this
It's the recursion(configObj, level=0, type='root', parentID=1) calls that are causing trouble. You think that level=0 is saying to pass 0 to the level parameter but javascript doesn't recognize that syntax. It thinks that level is some variable you forgot to define. Hence the is not defined error.
To fix the issue, just do something like recursion(configObj, 0, 'root', 1) instead.
Hello, I want to make a basic visual editor for my plugins.
let x = {
tag : "a",
atts : {
href : "/",
class : "a",
text:"link"
},
components:[
{
tag : "b",
atts : {
class : "a",
text:"asdsad"
},
components:[
//...
]
}
]
}
I have an js object like this. I want to get all "components" properties in this.
function render_blocks(blocks){
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i];
let $block_html = $("<"+ block.tag +">",{...block.atts});
if(block.components){
for (let k = 0; k < block.components.length; k++) {
const block_comp = block.components[k];
let $block_html_comp = $("<"+ block_comp.tag +">",{...block_comp.atts});
$block_html.html($block_html.html()+$block_html_comp[0].outerHTML);
}
}
html = $block_html[0].outerHTML;
console.log(html);
}
}
I am using a this function to convert js blocks to html. However this func is very bad :P.
Please HELLLP...
-Edit:
How can I scan nested components properties in my object? They may be a lot of. I am searching a efficient way.
You can use recursion
let x = {
tag: "a",
atts: {
href: "/",
class: "a",
text: "link"
},
components: [
{
tag: "b",
atts: {
class: "a",
text: "asdsad"
},
components: [{ last: "last" }]
}
]
};
let componentsArray = [];
function getComponents(obj) {
if (!obj.components) {
return;
}
componentsArray.push(obj.components);
obj.components.forEach(component => getComponents(component));
}
getComponents(x);
console.log("componentsArray ", componentsArray);
I solved my problem myself.
Answer
// sample blocks
let x = {
tag: "a",
atts: {
href: "/",
class: "a"
},
components: [{
tag: "b",
atts: {
class: "a",
text: "asdsad"
},
components: [{
tag: "b",
atts: {
class: "a",
text: "asdsad"
},
components: [
//...
]
}]
}]
}
function Block(block) {
this.components = []
if (block.components) {
this.components = block.components;
}
this.block = block;
}
Block.prototype.get_components = function() {
return (this.components ? (this.components.length <= 0 ? false : this.components) : false);
}
Block.prototype.find_inner_components = function() {
let has_components = this.get_components();
let parent_components_arr = [];
let section_components_arr = [];
while (has_components) {
let cur_components = has_components;
has_components = false;
for (let i = 0; i < cur_components.length; i++) {
let new_block = new Block(cur_components[i]);
section_components_arr.push(new_block);
has_components = has_components || new_block.get_components();
}
parent_components_arr.push(section_components_arr);
section_components_arr = [];
}
return parent_components_arr;
}
let a = new Block(x);
console.log(a.find_inner_components())
I would like to have a function called getSelectedValues which retrieves data from the options array instead of a variable called SelectedValues ( which is the way I have it now). The variable Selected Values currently gets the values that are true inside of the options array and assigns them to itself.
I simply would like to make this a function instead. (something called getSelectedValues I would imagine) How do I achieve this?
var options = [
{
name: "Red Pepper",
"selected": false,
value: "5.99"
},
{
name: "Garlic",
"selected": true,
value: "5.99"
},
{
name: "Tomatoes",
"selected": true,
value: "5.99"
},
]
var SelectedValues = options.filter(function (option) {
return (option.selected);
});
console.log(SelectedValues)
Just for reference, read more:
Declaring functions in JavaScript
function filterOptions(options) {
return options.filter(i => i.selected);
}
function filterOptions(options) {
return options.filter((i) => i.selected);
}
var options = [
{
name: "Red Pepper",
selected: false,
value: "5.99",
},
{
name: "Garlic",
selected: true,
value: "5.99",
},
{
name: "Tomatoes",
selected: true,
value: "5.99",
},
];
var selectedValues = filterOptions(options);
console.log(selectedValues);
.as-console {
min-height: 100% !important;
}
.as-console-row {
color: blue !important;
}
Something like this?
function getSelectedValues(options) {
const size = Object.keys(options).length;
for (var i = 0; i < size; i = i + 1) {
const isSelected = options[i]["selected"];
if (isSelected) {
alert(options[i].name);
}
}
}
Jsfiddle here: https://jsfiddle.net/z3nrh8Ly/50/
function getSelectedValues() {
return options.filter(t => t.selected);
}
another way:
getSelectedValues = () => options.filter(t => t.selected);
The issue detail:
1. I implement the feature with the vue-slider-component module, but that has a lot of warnings when I move the dots on the slider.
2. I know that the reason is that I used v-for to point to an object that will change, but I do not know how to fix this issue.
the following link is my test site:
https://jsfiddle.net/ncwv84x9/
enter image description here
My codes:
code1 (Html)
<div id="app">
<div class="box" v-for="(item,index) in columnvalue">
<label>{{item.text}}</label>
<input v-model="value[index]" />
</div>
<hr />
<br />
<vue-slider v-model="value" :order="false" :tooltip="'always'" :process="false" :marks="marks" :width="600">
<template slot="tooltip" slot-scope="{index}">
<div>{{getText(index)}}</div>
</template>
</vue-slider>
</div>
JavaScript + Vue:
new Vue({
el: '#app',
components: {
VueSlider: window['vue-slider-component']
},
data: function() {
return {
// collect the all values
columnvalue: [],
// stored disease value
pet_name: [{
text: 'dog',
index: 0
},
{
text: 'cat',
index: 1
}
],
// stored drug value
feeder_name: [{
text: 'Sam',
index: 0
}],
// from age filter
age: [
65, 100
],
test: "",
value: [],
process: dotsPos => [
[dotsPos[0], dotsPos[1], {
backgroundColor: 'pink'
}],
[dotsPos[1], dotsPos[2], {
backgroundColor: 'blue'
}],
[dotsPos[2], dotsPos[3], {
backgroundColor: 'black'
}],
],
after: {},
relations: [],
marks: {
'0': {
label: 'start',
margin: '0 0 0 10px'
},
'100': {
label: 'end',
labelStyle: {
left: '100%',
margin: '0 0 0 10px',
top: '50%',
transform: 'translateY(-50%)'
}
}
}
}
},
created: function() {
//vue instance 被 constructor 建立後,在這裡完成 data binding
let tmpArray = this.pet_name.concat(this.feeder_name);
let tmpValueArray = [];
for (i = 0; i < tmpArray.length; i++) {
tmpArray[i].index = i;
tmpValueArray.push(0);
}
this.columnvalue = tmpArray;
this.value = tmpValueArray;
},
methods: {
getText(index) {
const ani = this.columnvalue.find((v) => v.index == index).text;
this.after = {
...this.after,
[ani]: this.value[index]
}
return ani;
},
getNodeRelation() {
const indexs = this.after;
let result = [];
let result2 = [];
let placement = [];
for (obj in indexs) {
placement.push([obj, indexs[obj]]);
}
placement.sort(function(a, b) {
/* console.log(a[1]) */
return a[1] - b[1];
})
for (i = 0; i < placement.length; i++) {
if (i + 1 >= placement.length) {
break;
}
let distance = placement[i + 1][1] - placement[i][1];
let predicate = "";
if (distance > 0) {
predicate = "after";
} else if (distance == 0 && placement[i + 1][1] == 0) {
predicate = "hasUse";
} else {
predicate = "same";
}
let source = {
label: placement[i][0],
index: i
};
let target = {
label: placement[i + 1][0],
index: i
};
// store the 4-tuple reprsentations about slider
result2.push({
source: source,
target: target,
type: predicate,
days: distance
});
}
/* this.relations = "{\"relation\":" + JSON.stringify(result2)+"}" */
;
this.relations = JSON.stringify(result2);
},
getAllFilters() {
let vm = this;
let beginHas = true;
if (vm.relations.length == 0) {
vm.getNodeRelation();
beginHas = false;
}
let result = {
age: vm.age,
disease_name: vm.disease_name,
drug_name: vm.drug_name,
relation: vm.relations
};
if (!beginHas) {
vm.relations = [];
}
this.test = JSON.stringify(result);
}
},
})
I get a infinite loop error which disappears when I remove this section in getText()
this.after = {
...this.after,
[ani]: this.value[index]
}
This is because there is some reactivity triggered and re-renders the dom, which calls that function, which renders the dom and so on...
I need to search for an element in a json object like this:
var new_a = 'new';
var json = { cells:
[ { type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
},
{ type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}
]
}
Now I want to find the object with the id = 5aef826a1809, because I want to change the value of a to new_a or insert an a-element if it doesn't exist.
If id = 2c11b8bd8112 a new a-element with the content new_a should be added.
I tried to use
var res = _.find(json.cells, { id: '5aef826a1809' }); // doesn't work
res.attrs.a = new_a; // this would update or add new field, right?
But this doesn't work
Try like this
var new_a = 'new';
var json = {
cells: [{
type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
}, {
type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}]
};
var obj = json.cells.find(function (x) {
return x.id == '5aef826a1809'
});
if (obj) { // return value if found else return undefined if not found
obj.attrs.a = new_a;
console.log(json);
}
JSFIDDLE
Using this simple for loop should work, if that's what you're looking for:
for(var i = 0; i<json.cells.length; i++){
if(json.cells[i].id == "5aef826a1809" || json.cells[i].id == "2c11b8bd8112"){
json.cells[i].attrs.a = "new_a";
}
}
Hope it helped.
You can use Array.prototype.some for searching, changing and for making a short circuit to prevent more iteration than necessary.
var new_a = 'new',
json = {
cells: [{
type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
}, {
type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}]
};
function change(id) {
json.cells.some(function (a) {
var i = id.indexOf(a.id);
if (~i) {
a.attrs = a.attrs || {};
a.attrs.a = new_a;
id.splice(i, 1);
if (!id.length) {
return true;
}
}
});
}
change(['5aef826a1809', '2c11b8bd8112']);
document.write('<pre>' + JSON.stringify(json, 0, 4) + '</pre>');