-2

I am currently making a forum with

  • Basic techs: HTML, CSS, JavaScript and NodeJS
  • To retrieve data from API, using JSON file name. eg. \json\myfile.json

I am able to GET request for using JSON apis but not able to delete them.

Here's my code:

JSON:

[
  {
    "title": "Hello World !",
    "content": "1111111"
  },
  {
    "title": "Lorem Ipsum",
    "content": "22222222"
  },
  {
    "title": "azertyuiop",
    "content": "33333333"
  }
]

HTML:

<div id="element"></div>

  <div id="newElement">
    <input id="newTitle" type="text" value="">
    <input id="newContent" type="text" value="">
    <button type="button" name="addElement" onclick="addElement()">Add</button>
  </div>

JavaScript:

 'use strict';

  function loadJSON(callback) {
    var xobj = new XMLHttpRequest();
    xobj.overrideMimeType("application/json");
    xobj.open('GET', 'json/elements.json', true);
    xobj.onreadystatechange = function() {
      if (xobj.readyState == 4 && xobj.status == "200") {
        callback(xobj.responseText);
      }
    };
    xobj.send(null);
  }

  function getElements() {
    loadJSON(function(response) {
      var elements = JSON.parse(response);
      var containerElement = document.getElementById("element");
      var titleElement;
      var contentElement;
      var deleteElement;
      for (var i = 0; i < elements.length; i++) {
        titleElement = document.createElement("h1");
        contentElement = document.createElement("p");
        deleteElement = document.createElement("button");
        containerElement.appendChild(titleElement);
        containerElement.appendChild(contentElement);
        containerElement.appendChild(deleteElement);
        titleElement.innerHTML = elements[i].title;
        contentElement.innerHTML = elements[i].content;
        deleteElement.innerHTML = "Delete";
        deleteElement.addEventListener('click', function() {
          console.log(titleElement[i]);
          console.log(contentElement[i]);
        });
      }
    });
  }

function addElement() {
    loadJSON(function(response) {
      var elements = JSON.parse(response);
      var newTitle = document.getElementById('newTitle').value;
      var newContent = document.getElementById('newContent').value;
      console.log("Title: " + newTitle + "     " + "Content: " + 
newContent);
    });
  }

  getElements();

I looked at how the closures worked but I don't know how to apply them to my code, it returns me undefined after I log the contentElement and the titleElement.

Ivar
  • 6,138
  • 12
  • 49
  • 61
Vivien
  • 1
  • 1
  • 1
    There is nothing in the code or markup that mentions deleting anything. You need to give us a short, basic example of what you're trying to do. See how to create a [MCVE] – Reinstate Monica Cellio Nov 21 '17 at 09:18
  • 1
    *"Delete a JSON element..."* Once you've parsed it, it's not JSON anymore. JSON is a *textual notation* for data exchange. [(More here.)](http://stackoverflow.com/a/2904181/157247) If you're dealing with JavaScript source code, and not dealing with a *string*, you're not dealing with JSON. – T.J. Crowder Nov 21 '17 at 09:19
  • Moreover, you're not keeping the parsed result. – T.J. Crowder Nov 21 '17 at 09:19
  • push full code i will help u out – D V Yogesh Nov 21 '17 at 09:21
  • Your profile says you've been back. Did either of the answers below answer your question? If not, perhaps post a comment asking for more info, or edit the question... – T.J. Crowder Nov 21 '17 at 17:44

1 Answers1

-1

You're really close. The issue with getting undefined for contentElement and titleElement is described in this question's answers, but the answers there, being general, don't give you the simplest way to deal with it in your case.

See comments:

function getElements() {
    loadJSON(function(response) {
        var elements = JSON.parse(response);
        var containerElement = document.getElementById("element");
        var entryElement;
        var titleElement;
        var contentElement;
        var deleteElement;
        for (var i = 0; i < elements.length; i++) {
            // Create a container for the entry; let's give it a class we'll
            //  use later as well
            entryElement = document.createElement("div");
            entryElement.className = "entry";
            titleElement = document.createElement("h1");
            contentElement = document.createElement("p");
            deleteElement = document.createElement("button");
            // Put these in the entry's container
            entryElement.appendChild(titleElement);
            entryElement.appendChild(contentElement);
            entryElement.appendChild(deleteElement);
            titleElement.innerHTML = elements[i].title;
            contentElement.innerHTML = elements[i].content;
            deleteElement.innerHTML = "Delete";
            deleteElement.addEventListener('click', function() {
                // Here, `this` refers to the delete button that was clicked;
                // remove its parent element:
                var parent = this.parentNode;
                parent.parentNode.removeChild(parent);
            });
            // Add the entry to the main container
            containerElement.appendChild(entryElement);
        }
    });
}

Separately, there's no need to re-load the JSON in addElement, just add a new element live to the page. In fact, since we want to do that both when creating the elements from the JSON and when adding a new one, let's put that in a function, then reuse that function:

'use strict'

var json = '[{' +
    '"title": "Hello World !",' +
    '"content": "1111111"' +
    '},' +
    '{' +
    '"title": "Lorem Ipsum",' +
    '"content": "22222222"' +
    '},' +
    '{' +
    '"title": "azertyuiop",' +
    '"content": "33333333"' +
    '}' +
    ']';

function loadJSON(callback) {
    // Simulate the ajax
    setTimeout(callback, 200, json);
    /*
    var xobj = new XMLHttpRequest();
    xobj.overrideMimeType("application/json");
    xobj.open('GET', 'json/elements.json', true);
    xobj.onreadystatechange = function() {
        if (xobj.readyState == 4 && xobj.status == "200") {
            callback(xobj.responseText);
        }
    };
    xobj.send(null);
    */
}

function addElement(title, content) {
    // Create a container for the entry
    var entryElement = document.createElement("div");
    entryElement.className = "entry";
    // And the things to put in it
    var titleElement = document.createElement("h1");
    var contentElement = document.createElement("p");
    var deleteElement = document.createElement("button");
    // Put these in the entry's container
    entryElement.appendChild(titleElement);
    entryElement.appendChild(contentElement);
    entryElement.appendChild(deleteElement);
    // You might consider HTML-escaping things, here's how
    titleElement.appendChild(document.createTextNode(title));
    contentElement.appendChild(document.createTextNode(content));
    deleteElement.innerHTML = "Delete";
    deleteElement.addEventListener('click', function() {
        // Here, `this` refers to the delete button that was clicked;
        // remove its parent element:
        var parent = this.parentNode;
        parent.parentNode.removeChild(parent);
    });
    // Add the entry to the main container
    document.getElementById("element").appendChild(entryElement);
}

function getElements() {
    loadJSON(function(response) {
        var elements = JSON.parse(response);
        for (var i = 0; i < elements.length; i++) {
            // Call our reusable function
            addElement(elements[i].title, elements[i].content);
        }
    });
}

function addElementClick() {
    // Just call our reusable function
    addElement(document.getElementById('newTitle').value, document.getElementById('newContent').value);
}

getElements();
<div id="element"></div>
    
      <div id="newElement">
        <input id="newTitle" type="text" value="">
        <input id="newContent" type="text" value="">
        <button type="button" name="addElement" onclick="addElementClick()">Add</button>
      </div>

Note that there I renamed your original addElement to addElementClick and had a new addElement function accept the title and content as parameters.

If at some stage you want to rebuild the elements array, you can readily do that by retrieving the data from the DOM:

function getElementsFromUI() {
    var elements = [];
    document.querySelector(".entry").forEach(function(entryElement) {
        elements.push({
            title: entryElement.querySelector("h1").innerHTML,
            content: entryElement.querySelector("p").innerHTML
        });
    });
    return elements;
}

The NodeList returned by querySelectorAll only recently got forEach, but you can easily polyfill it on older browsers:

if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
    Object.defineProperty(NodeList.prototype, "forEach", {
        value: Array.prototype.forEach,
        configurable: true,
        enumerable: true
    });
}

Live Example:

'use strict'

var json = '[{' +
    '"title": "Hello World !",' +
    '"content": "1111111"' +
    '},' +
    '{' +
    '"title": "Lorem Ipsum",' +
    '"content": "22222222"' +
    '},' +
    '{' +
    '"title": "azertyuiop",' +
    '"content": "33333333"' +
    '}' +
    ']';

if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
    Object.defineProperty(NodeList.prototype, "forEach", {
        value: Array.prototype.forEach,
        configurable: true,
        enumerable: true
    });
}

function loadJSON(callback) {
    // Simulate the ajax
    setTimeout(callback, 200, json);
    /*
    var xobj = new XMLHttpRequest();
    xobj.overrideMimeType("application/json");
    xobj.open('GET', 'json/elements.json', true);
    xobj.onreadystatechange = function() {
        if (xobj.readyState == 4 && xobj.status == "200") {
            callback(xobj.responseText);
        }
    };
    xobj.send(null);
    */
}

function addElement(title, content) {
    // Create a container for the entry
    var entryElement = document.createElement("div");
    entryElement.className = "entry";
    // And the things to put in it
    var titleElement = document.createElement("h1");
    var contentElement = document.createElement("p");
    var deleteElement = document.createElement("button");
    // Put these in the entry's container
    entryElement.appendChild(titleElement);
    entryElement.appendChild(contentElement);
    entryElement.appendChild(deleteElement);
    // You might consider HTML-escaping things, here's how
    titleElement.appendChild(document.createTextNode(title));
    contentElement.appendChild(document.createTextNode(content));
    deleteElement.innerHTML = "Delete";
    deleteElement.addEventListener('click', function() {
        // Here, `this` refers to the delete button that was clicked;
        // remove its parent element:
        var parent = this.parentNode;
        parent.parentNode.removeChild(parent);
    });
    // Add the entry to the main container
    document.getElementById("element").appendChild(entryElement);
}

function getElements() {
    loadJSON(function(response) {
        var elements = JSON.parse(response);
        for (var i = 0; i < elements.length; i++) {
            // Call our reusable function
            addElement(elements[i].title, elements[i].content);
        }
    });
}

function addElementClick() {
    // Just call our reusable function
    addElement(document.getElementById('newTitle').value, document.getElementById('newContent').value);
}

function getElementsFromUI() {
    var elements = [];
    document.querySelectorAll(".entry").forEach(function(entryElement) {
        elements.push({
            title: entryElement.querySelector("h1").innerHTML,
            content: entryElement.querySelector("p").innerHTML
        });
    });
    return elements;
}

document.getElementById("btnShow").addEventListener("click", function() {
    console.log(getElementsFromUI());
});
getElements();
.as-console-wrapper {
  max-height: 100% !important;
}
<input type="button" id="btnShow" value="Show Elements">
<div id="element"></div>
<div id="newElement">
  <input id="newTitle" type="text" value="">
  <input id="newContent" type="text" value="">
  <button type="button" name="addElement" onclick="addElementClick()">Add</button>
</div>

Alternately, you could keep a copy of the elements array around and ensure that you both remove the DOM structure for an entry and remove the entry, and similar ensure adding is done in parallel, but then you're writing code to maintain two lists of things, which almost inevitably leads to updating one but forgetting to update the other. Various "live bindings" libraries try to help there by having you just maintain your elements array and then have the DOM updated based on it, such as Knockout, Vue, React, Angular, and a dozen others. (Some are quite simple and drop easily in to any project; others are much more complex and take the "you do your app OUR way" approach. :-) ) For anything non-trivial, it's probably worth looking at something like that.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875