瀏覽代碼

first commit

Dominique Clarke 6 年之前
當前提交
d46ff95873
共有 1 個檔案被更改,包括 682 行新增0 行删除
  1. 682
    0
      README.md

+ 682
- 0
README.md 查看文件

@@ -0,0 +1,682 @@
1
+# ZCW-MesoLabs-YouAreEllClient
2
+
3
+## **Objective:**
4
+* Write a font-end client that interacts with the YouAreEll RESTful API. 
5
+* The client should visually display the user's message threads, with each thread containing a list of messages to and from another user.
6
+* The client should allow the user to post a new message to a particular user.
7
+
8
+## **Constraint:**
9
+* No front end frameworks or libraries, including JQuery.
10
+* This project uses the latest JavaScript features, many of which are not available in browsers without using a transpiling technology. To avoid using a transpiller, you **MUST USE GOOGLE CHROME** for this lab.
11
+
12
+### **Purpose:**
13
+* To establish familiarity with
14
+    * HTML
15
+    * HTML forms
16
+    * CSS
17
+    * JavaScript
18
+    * JavaScript Modules
19
+    * The Document Object Model
20
+    * Http requests
21
+
22
+### **Resources:**
23
+* [Intro to HTML, CSS, and JS]()
24
+* [MDN](https://developer.mozilla.org/en-US/docs/Learn)
25
+
26
+### Part 0.0 - Familiarize Yourself with the Project Structure
27
+
28
+* Your project contains two files, ``index.html``, ``index.js`` and ``styles.css``, providing you with the basic html structure of the project and some basic styles.
29
+
30
+### Part 0.1 - Serve your project
31
+
32
+* Navigate to your project directory in the command line. Run the command ``python -m SimpleHTTPServer 8000``. This will expose the project on ``localhost:8000``. Navigate there in your browser to view your project.
33
+
34
+### Part 1.0 - Creating you JavaScript file
35
+
36
+* Create a new file in the project directory called ``index.js``.
37
+* Link this file in the ``<head>`` of your ``index.html`` file, using the ``<script>`` tag.
38
+    * In addition to src, you'll need two extra attributes on your ``<script>`` tag, ``type`` and ``async``.
39
+    * For the ``type`` attribute, assign it a value of ``module``. This denotes that the file should be treated as a JavaScript module. Normally, JavaScript files are executed immediately once they are downloaded, even if the HTML hasn't finished parsing yet. We'll explore the benefits of JavaScirpt modules throughout this lab, but one benefit is that the executive of ``modules`` is ``deferred`` until after the HTML is Parsed. 
40
+    [Read more about JavaScript modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/)
41
+    * For the ``async`` attribute, assign it a value of ``true``. Typically, when an HTML file hits a ``<script>`` tag, it stops parsing the HTML, downloads the JavaScript, and then executes the JavaScript. ``async="true"`` overrides this behavior, instead allowing the HTML to be parsed **alongside** downloading the JavaScript. Once the JavaScript is finished downloading, the HTML parsing is paused and the script executes. [Read more about async and defer](https://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html)
42
+* At the top of your ``index.html`` file, declare a new variable called ``currentUser`` and assign it your YouAreEll username (You should have made one in the previous YouAreEll lab).
43
+* [Add an event listener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to the [``window``](https://developer.mozilla.org/en-US/docs/Web/API/Window) object. The ``addEventListener`` method takes two parameters, the type of event you're listening for (examples include "load", "click", "keydown", etc), and a function reference, known as a [callback](), representing the function you want to invoke when the event occurs. Wraping code in a "load" event listener attached to the ``window`` object will insure that your code is only ran once the page has loaded.
44
+* 
45
+```javascript
46
+let userId = "dominiqueclarke";
47
+
48
+window.addEventListener("load", function () {
49
+
50
+});
51
+```
52
+* Our goal is to add some text to the ``<h2`` element, nested within the ``header`` element containing the ``id`` of ``greeting``. In order to do so, we need to grab this element off the [``document``](https://developer.mozilla.org/en-US/docs/Web/API/Document) object 
53
+* Use the [``getElementById``](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) method to grab the element containing the id ``greeting``. This will return to you an object of type [``element``](https://developer.mozilla.org/en-US/docs/Web/API/Element), allowing you to use any of the methods or access any of the properites available on the element interface.
54
+* Assign the [``innerHTML``](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) property the [template string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) ``` `Welcome ${userId}` ```
55
+```javascript
56
+let userId = "dominiqueclarke";
57
+
58
+window.addEventListener("load", function () {
59
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
60
+});
61
+```
62
+* Refresh your page to view your changes
63
+
64
+### Part 2.0 - Create Your Service
65
+
66
+* Create a new JavaScript file called ``message-serivce.js``. This file will contain a [JavaScript class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) called ``MessageService``, responsible for making HTTP requests to fetch and update data from the YouAreEll RESTful API.
67
+```javascript
68
+class MessageService {
69
+   
70
+}
71
+```
72
+* Configure your ``MessageService`` as a module. 
73
+    * In JavaScript, the word "modules" refers to small units of independent, reusable code. They are the foundation of many JavaScript design patterns and are critically necessary when building any non-trivial JavaScript-based application. The closest analog in the Java language are Java Classes. However, JavaScript modules export a value, rather than define a type. In practice, most JavaScript modules export an object literal, a function, or a constructor. Modules that export a string containing an HTML template or a CSS stylesheet are also common.
74
+    * The [``export``](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) statement is used when creating JavaScript modules to export functions, objects, classes or primitive values from the module so they can be used by other programs with the import statement.
75
+    * ``export`` your ``MessageService`` as the ``default``.
76
+```javascript
77
+export default class MessageService {
78
+
79
+}
80
+```
81
+* Import your MessageService module into your ``index.js`` file using the [``import``](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import) statement. This creates a global variable containing the exported value from the imported module.
82
+```javascript
83
+import MessageService from "./message-service.js";
84
+
85
+let userId = "dominiqueclarke";
86
+
87
+window.addEventListener("load", function () {
88
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
89
+});
90
+```
91
+* Create a new ``MessageService`` object by using the ``new`` keyword to invoke the ``MessageService`` constructor.
92
+```javascript
93
+import MessageService from "./message-service.js";
94
+
95
+let userId = "dominiqueclarke";
96
+const messageService = new MessageService();
97
+
98
+window.addEventListener("load", function () {
99
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
100
+});
101
+```
102
+
103
+### Part 3.0 - Creating AJAX HTTP Requests
104
+
105
+* In ``message-service.js``, create a method called ``getAllMessages``, which takes a single parameter, ``userId``.
106
+* Create a ``XMLHTTPRequest`` (XHR) object and assign it to a variable called ``request``. XMLHttpRequest (XHR) objects  interact with servers through ``HTTP`` requests. You can retrieve data from a URL without having to do a full page refresh. XMLHttpRequest is used heavily in [Ajax](https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX/Getting_Started) programming.
107
+* Use the [``open``](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open) method on the ``request`` object, passing the type of ``HTTP`` request you'd like to make and the request endpoint as the first two arguments. To get all the global messages, use the ``/messages/`` endpoint. Refer back to the original [YouAreEll lab](https://git.zipcode.rocks/ZipCodeWilmington/YouAreEll) for documentation on the API if necessary.
108
+* Use the [``send``](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) method to send the request. This method takes an optional parameter of the request ``body`` when necessary.
109
+```javascript
110
+export default class MessageService {
111
+
112
+    getAllMessages(userId) {
113
+        let request = new XMLHttpRequest();
114
+
115
+        request.open("GET", "http://zipcode.rocks:8085/messages");
116
+
117
+        request.send();
118
+    }
119
+}
120
+```
121
+
122
+### Part 3.5 - Listening for Request Responses
123
+
124
+* We've configured and sent the request, but what happens when we receive the request back? We can define a function to be used once the response is received using the [``onload``](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload) property of the ``request`` object.
125
+```javascript
126
+getAllMessages(userId) {
127
+    let request = new XMLHttpRequest();
128
+
129
+    // Setup our listener to process compeleted requests
130
+    request.onload = function() {
131
+        // do something
132
+    };
133
+
134
+    request.open("GET", `http://zipcode.rocks:8085/messages`);
135
+
136
+    request.send();
137
+}
138
+```
139
+* If the status is greater than or equal to 200 and less than 300, than we have a successful response. Else, we have an error. Create an if/else statement to handle the response or error.
140
+* The response is stored in the ``responseText`` property of the ``request`` object as an array of [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) objects. To convert it into an array of JavaScript objects, use ``JSON.parse(request.responseText)``. 
141
+```javascript
142
+getAllMessages(userId) {
143
+    let request = new XMLHttpRequest();
144
+
145
+    // Setup our listener to process compeleted requests
146
+    request.onload = function() {
147
+        if (request.status >= 200 && request.status < 300) {
148
+            console.log(JSON.parse(request.responseText)); // 'This is the returned text.'
149
+        } else {
150
+            console.log('Error: ' + request.status); // An error occurred during the request.
151
+        }
152
+    };
153
+
154
+    request.open("GET", "http://zipcode.rocks:8085/messages");
155
+
156
+    request.send();
157
+}
158
+```
159
+* Test the function by navigating back to ``index.js`` and invoking the function.
160
+```javascript
161
+import MessageService from "./message-service.js";
162
+
163
+let userId = "dominiqueclarke";
164
+const messageService = new MessageService(userId);
165
+
166
+window.addEventListener("load", function () {
167
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
168
+    messageService.getAllMessages(userId);
169
+});
170
+```
171
+* Refresh your browser. Right click on the page and select ``inspect``. When the dev tools container pops up, click the ``console`` tab. Once the response is returned, you should see the returned array of messages printed to the console.
172
+
173
+<!-- ## Part 3.7 - Convert Message Array to Threads Object
174
+
175
+* Our API returns an array of messages from various users. Create a helper method on ``MessageService`` class called ``parseThreads`` to convert this array into an object. Our object will act kinda like a hashmap, with a key representing the ``fromId``, and the value being an array of messages with that ``fromId``. ``parseThreads`` should take one parameter, the array of ``messages``. Looping through the array, check to see if the ``threads`` object has a key for the current message's ``fromId``. If not, first create the new key and assign it an empty array, then push the message to the array. If the ``threads`` object does contain a key representing the current message's ``fromId``, push the message to the array. Once you've iterated through the messages, return the ``threads`` object.
176
+
177
+```javascript
178
+parseThreads(messages) {
179
+    const threads = {};
180
+
181
+    messages.forEach(message => { 
182
+        if (!threads.hasOwnProperty(message.fromid)) {
183
+            threads[message.fromid] = [];
184
+            threads[message.fromid].push(message);
185
+        } else {
186
+            threads[message.fromid].push(message);
187
+        }
188
+    });  
189
+
190
+    return threads;
191
+}
192
+```
193
+* Using the ``parseThreads`` method, edit your ``getAllMessages`` function to parse the ``response.responseText`` from an array to an object.
194
+    * You may be tempted to call the function using the ``this`` keyword. Keep in mind that ``this`` within the ``onload`` function refers to the ``request`` object, not the ``MessageService`` object. In order to refer to the ``MessageService`` within ``request.onload``, we need to capture the context of ``MessageService`` in a new variable called ``self``. This will capture the context of the ``MessageService`` object, and you can use ``self`` as opposed to ``this`` to refer to the ``MessageService`` object.
195
+```javascript
196
+getAllMessages(userId) {
197
+    let request = new XMLHttpRequest();
198
+    let self = this;
199
+
200
+    // Setup our listener to process compeleted requests
201
+    request.onload = function() {
202
+        if (request.status >= 200 && request.status < 300) {
203
+            console.log(self.parseThreads(JSON.parse(request.responseText))); // 'This is the returned text.'
204
+        } else {
205
+            console.log('Error: ' + request.status); // An error occurred during the request.
206
+        }
207
+    };
208
+
209
+    request.open("GET", `${this.apiUri}/ids/${userId}/messages`);
210
+
211
+    request.send();
212
+}
213
+``` -->
214
+* Refresh the page and check your console for your outputted ``threads`` object.
215
+
216
+### Part 4.0 - Promise based AJAX requests
217
+
218
+* Our current ``getAllMessages`` method has some issues. XMLHTTPRequests are processed asynchronously using callbacks. Callbacks cannot contain a return value. This makes it difficult to pass back a value to ``index.js`` where this ``messageService.getAllMessages(userId)`` is being called. Fortunately, we can alieviate this issue using [``promises``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
219
+    * A [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) is an object representing a contract to preform some task asynchronous (often, an ``HTTP`` request), providing a value (often, an ``HTTP`` response) when the task is complete.
220
+    * Promises allow us to continue running syncronous code while waiting for for the execution of the promised task.
221
+    * Promises allow us to specify a function that should be run once the task is complete using the ``then`` method.
222
+    * Promises are tricky. Familiarize yourself with Promises with [this tutorial](https://www.sitepoint.com/overview-javascript-promises/)
223
+* Wrap your ``request.onload`` function in a ``new`` ``Promise``;
224
+```javascript
225
+getAllMessages(userId) {
226
+    const request = new XMLHttpRequest();
227
+
228
+    new Promise(function (resolve, reject) {
229
+        // Setup our listener to process compeleted requests
230
+        request.onload = function () {
231
+            // Process the response
232
+            if (request.status >= 200 && request.status < 300) {
233
+                console.log(JSON.parse(request.responseText)); // 'This is the returned text.'
234
+            } else {
235
+                console.log('Error: ' + request.status); // An error occurred during the request.
236
+            }
237
+        };
238
+
239
+        request.open("GET", "http://zipcode.rocks:8085/messages");
240
+
241
+        request.send();
242
+    });
243
+}
244
+```
245
+* If the request is successful, ``resolve`` the ``promise`` passing in the ``threads`` object``
246
+```javascript
247
+getAllMessages(userId) {
248
+    const request = new XMLHttpRequest();
249
+
250
+    new Promise(function (resolve, reject) {
251
+        // Setup our listener to process compeleted requests
252
+        request.onload = function () {
253
+            // Process the response
254
+            if (request.status >= 200 && request.status < 300) {
255
+                const threads = JSON.parse(request.responseText); // 'This is the returned text.'
256
+                resolve(threads);
257
+            } else {
258
+                console.log('Error: ' + request.status); // An error occurred during the request.
259
+            }
260
+        };
261
+
262
+        request.open("GET", "http://zipcode.rocks:8085/messages");
263
+
264
+        request.send();
265
+    });
266
+}
267
+```
268
+* If the request returns an error, ``reject`` the ``promise`` passing in the ``threads`` object``
269
+```javascript
270
+getAllMessages(userId) {
271
+    const request = new XMLHttpRequest();
272
+
273
+    new Promise(function (resolve, reject) {
274
+        // Setup our listener to process compeleted requests
275
+        request.onload = function () {
276
+            // Process the response
277
+            if (request.status >= 200 && request.status < 300) {
278
+                const threads = JSON.parse(request.responseText); // 'This is the returned text.'
279
+                resolve(threads);
280
+            } else {
281
+                reject({
282
+                    status: request.status,
283
+                    statusText: request.statusText
284
+                });
285
+            }
286
+        };
287
+
288
+        request.open("GET", "http://zipcode.rocks:8085/messages");
289
+
290
+        request.send();
291
+    });
292
+}
293
+```
294
+* Specify the function you'd like executed when the promise is resolved by using the ``then`` method.
295
+    * The [``then``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) method is part of the ``Promise`` interface. It takes up to two parameters: a ``callback`` function for the success case and a callback function for the failure case of the ``Promise``.
296
+    * If the ``Promise`` is successful, the first parameter (the success callback), is executed. If the ``Promise`` results in an error, the second parameter (the failure callback), is excuted.  
297
+```javascript
298
+getAllMessages(userId) {
299
+    const request = new XMLHttpRequest();
300
+
301
+    new Promise(function (resolve, reject) {
302
+        // Setup our listener to process compeleted requests
303
+        request.onload = function () {
304
+            // Process the response
305
+            if (request.status >= 200 && request.status < 300) {
306
+                // If successful
307
+                const threads = JSON.parse(request.responseText);
308
+                resolve(threads);
309
+            } else {
310
+                reject({
311
+                    status: request.status,
312
+                    statusText: request.statusText
313
+                });
314
+            }
315
+        };
316
+
317
+        request.open("GET", "http://zipcode.rocks:8085/messages");
318
+
319
+        request.send();
320
+    }).then(successCallback, errorCallback);
321
+
322
+    function successCallback() {
323
+        console.log("Promise is successful!");
324
+    }
325
+
326
+    function errorCallback() {
327
+        console.log("An error occurred");
328
+    }
329
+}
330
+```
331
+* When the callbacks are executed, the receive a special parameter. The success callback receives the value passed to the ``resolve`` method, while the failure callback receives the value passed to the ``reject`` method.
332
+```javascript
333
+getAllMessages(userId) {
334
+    const request = new XMLHttpRequest();
335
+
336
+    new Promise(function (resolve, reject) {
337
+        // Setup our listener to process compeleted requests
338
+        request.onload = function () {
339
+            // Process the response
340
+            if (request.status >= 200 && request.status < 300) {
341
+                // If successful
342
+                const threads = JSON.parse(request.responseText);
343
+                // this data is passed to the success callback
344
+                resolve(threads);
345
+            } else {
346
+                // this data is passed to the failure callback
347
+                reject({
348
+                    status: request.status,
349
+                    statusText: request.statusText
350
+                });
351
+            }
352
+        };
353
+
354
+        request.open("GET", "http://zipcode.rocks:8085/messages");
355
+
356
+        request.send();
357
+    }).then(successCallback, errorCallback);
358
+
359
+    function successCallback(response) {
360
+        // This data comes from the resolve method
361
+        console.log(response);
362
+    }
363
+
364
+    function errorCallback(response) {
365
+        // This data comes from the reject method
366
+        console.log(response);
367
+    }
368
+}
369
+```
370
+
371
+### Part 5.0 - Consuming the Promise elsewhere
372
+
373
+* By refactoring our ``getAllMessages`` method, we can consume the ``Promise`` within our ``index.js`` file, allowing for separation of concerns.
374
+* Remove the ``then`` method, ``successCallback`` declaration and ``errorCallback`` declaration from ``getAllMessages``.
375
+* ``return`` the Promise from the ``getAllMessages`` method. This will allow us to call the ``then`` method, passing in the appropriate success and failure callbacks, elsewhere. 
376
+```javascript
377
+getAllMessages(userId) {
378
+    const request = new XMLHttpRequest();
379
+
380
+    return new Promise(function (resolve, reject) {
381
+        // Setup our listener to process compeleted requests
382
+        request.onload = function () {
383
+            // Process the response
384
+            if (request.status >= 200 && request.status < 300) {
385
+                // If successful
386
+                const threads = JSON.parse(request.responseText);
387
+                // this data is passed to the success callback
388
+                resolve(threads);
389
+            } else {
390
+                // this data is passed to the failure callback
391
+                reject({
392
+                    status: request.status,
393
+                    statusText: request.statusText
394
+                });
395
+            }
396
+        };
397
+
398
+        request.open("GET", "http://zipcode.rocks:8085/messages");
399
+
400
+        request.send();
401
+    })
402
+}
403
+```
404
+* Navigate back to your ``index.js`` file. ``getAllMessages`` now returns a ``Promise``. We can now use the ``then`` method to specify a ``callback`` function to be executed in case of success or failure of that ``Promise``. Call ``.then`` on ``messageService.getAllMessages``, reimplementing the original code.
405
+```javascript
406
+messageService.getAllMessages(userId)
407
+    .then(successCallback, errorCallback);
408
+
409
+function successCallback(response) {
410
+    // This data comes from the resolve method
411
+    console.log(response);
412
+}
413
+
414
+function errorCallback(response) {
415
+    // This data comes from the reject method
416
+    console.log(response);
417
+}
418
+```
419
+### Part 6.0 - Populating the DOM
420
+
421
+* Now that we have our messages, let's add them to our page visually. Using the DOM interface, we can create and add HTML elements to our page.
422
+    * We'll populate our  messages inside the unordered list``<ul id="message-list">``.
423
+* Create a new function in ``index.js`` called ``populateMessages``. ``populateMessages`` should take one parameter, a list of messages.
424
+```javascript
425
+import MessageService from "./message-service.js";
426
+
427
+let userId = "dominiqueclarke";
428
+const messageService = new MessageService(userId);
429
+
430
+window.addEventListener("load", function () {
431
+
432
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
433
+    messageService.getAllMessages(userId)
434
+        .then(successCallback, errorCallback);
435
+
436
+    function successCallback(response) {
437
+        // This data comes from the resolve method
438
+        console.log(response);
439
+    }
440
+
441
+    function errorCallback(response) {
442
+        // This data comes from the reject method
443
+        console.log(response);
444
+    }
445
+});
446
+
447
+function populateMessages(messages) {
448
+
449
+}
450
+```
451
+* In order to add content to the ``DOM``, we need to create new ``nodes``. A [``node``](https://developer.mozilla.org/en-US/docs/Web/API/Node) is an interface is an interface from which a number of ``DOM`` API object types inherit, including ``document``, ``element`` and more. A ``node`` represents a piece of the ``DOM`` tree.
452
+* Using a ``forEach`` loop, loop through each message in the array of ``messages``.
453
+* For each message, create a new ``<li>`` ``element`` to hold the sender username and the message content and assign it to ``messageListItem``.
454
+    * You can do this by calling the ``createElement`` method on the ``document`` object, passing in the element tag name as a string. This will return a new HTML ``element`` that you can later append to the ``DOM``. Remember, ``elements`` are a type of ``node``.
455
+* For each message, create a new ``<h3>`` element for the sender username and assign it to ``const userIdHeading``.
456
+* For each message, create a new ``<p>`` element for the message content and assign it to ``const messageParagraph``.
457
+```javascript
458
+function populateThread(messages) {
459
+    messages.forEach(message => {
460
+        const messageListItem = document.createElement("LI"); 
461
+        const userIdHeading = document.createElement("h3");
462
+        const messageParagraph = document.createElement("p"); 
463
+    })
464
+}
465
+```
466
+* Both our ``<h3>`` element and our ``<p>`` element will contain text.
467
+    * To add new text to our page, we need to first create a new ``text node``. You can create a ``text node`` using the [``createTextNode``](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode) method on the ``document`` object, passing in the text you wish to include in the node. This will return a new ``text node`` that you can later append to an ``element``.
468
+* For each message, create a ``text node`` using the ``fromid`` property on the ``message`` object and assign it to const ``userIdContent``.
469
+* For each message, create a ``text node`` using the ``message`` property on the ``message`` object and assign it to ``const messageContent``.
470
+```javascript
471
+function populateThread(messages) {
472
+    messages.forEach(message => {
473
+        const messageListItem = document.createElement("LI");
474
+        const userIdHeading = document.createElement("h3");
475
+        const messageParagraph = document.createElement("p");
476
+        const messageContent = document.createTextNode(message.message);
477
+        const userIdContent = document.createTextNode(message.fromid);
478
+    })
479
+}
480
+```
481
+* Now that we've created these text nodes, we need to add them to our new html elements. 
482
+    * To add any node to another node, use the [``appendChild``] method. The ``Node.appendChild()`` method adds a node to the end of the list of children of a specified parent node. ``appendChild`` returns the modified ``node`` object, allowing you to perform method chaining.
483
+* Add your ``messageContent`` ``node`` to your ``messageParagraph`` ``node`` using the ``appendChild`` method.
484
+* Add your ``userIdContent`` ``node`` to your ``userIdHeading`` ``node`` using the ``appendChild`` method.
485
+* Add both your ``userIdHeading`` ``node`` and your ``messageParagraph`` ``node`` to your ``messageListItem`` node, using the ``appendChild`` method and method chaining.
486
+```javascript
487
+function populateThread(messages) {
488
+    messages.forEach(message => {
489
+        const messageListItem = document.createElement("LI");
490
+        const userIdHeading = document.createElement("h3");
491
+        const messageParagraph = document.createElement("p");
492
+        const messageContent = document.createTextNode(message.message);
493
+        const userIdContent = document.createTextNode(message.fromid);
494
+        userIdHeading.appendChild(userIdContent);
495
+        messageParagraph.appendChild(messageContent);
496
+        messageListItem
497
+            .appendChild(userIdHeading)
498
+            .appendChild(messageParagraph);
499
+    })
500
+}
501
+```
502
+* By using these methods, we've created a complete ``DOM`` ``node`` for each message that includes an ``<li>`` containing a ``<h3>`` ``element`` for the ``message.fromId`` and an ``<p>`` ``element`` for the ``message.message``.
503
+* Now that we've created our new ``node``, we need to add it to an existing HTML ``element`` on our page. Review the ``index.html`` file and find ``<ul id="message-list">``. We want to add all of our new individual ``<li>`` elements to this ``<ul>``. To grab this ``element`` using javascript, we can use the [``getElementById``](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) method on the ``document`` object, passing in the element's ``id`` as a string.
504
+* Using the ``appendChild`` method, append the ``messageListItem`` ``node`` to the ``element`` returned using ``document.getElementById("message-list")``. This will add a new ``<li>`` representing each message to our ``<ul id="message-list">`` element.
505
+```javascript
506
+function populateThread(messages) {
507
+    messages.forEach(message => {
508
+        const messageListItem = document.createElement("LI");
509
+        const userIdHeading = document.createElement("h3");
510
+        const messageParagraph = document.createElement("p");
511
+        const messageContent = document.createTextNode(message.message);
512
+        const userIdContent = document.createTextNode(message.fromid);
513
+        userIdHeading.appendChild(userIdContent);
514
+        messageParagraph.appendChild(messageContent);
515
+        messageListItem
516
+            .appendChild(userIdHeading)
517
+            .appendChild(messageParagraph);
518
+        document.getElementById("message-list").appendChild(messageListItem);
519
+    })
520
+}
521
+```
522
+* Now that we've created our message, let's invoke the function from our ``successCallback`` method, passing in the array of ``messages`` returned from our HTTP request.
523
+```javascript
524
+window.addEventListener("load", function () {
525
+    document.getElementById("greeting").innerHTML = `Welcome ${userId}!`;
526
+    messageService.getAllMessages(userId)
527
+        .then(successCallback, errorCallback);
528
+
529
+    function successCallback(response) {
530
+        // This data comes from the resolve method
531
+        populateMessages(response);
532
+    }
533
+
534
+    function errorCallback(response) {
535
+        // This data comes from the reject method
536
+        console.log(response);
537
+    }
538
+});
539
+```
540
+* Refresh your page to review the results and check for any errors
541
+
542
+### Part 7.0 - Creating A New Messages
543
+
544
+* Now that we've fetched all the current messages, let's send new messages out into the atmosphere.
545
+* Navigate to your ``message-service.js`` file. Add a new method called ``createNewMessage``. It should take one parameter, the new ``message`` object.
546
+* Set up your ``XMLHTTPRequest``. The set up is the same as our ``getAllMessages`` method, except for calling the ``request.open`` and ``request.send`` methods.
547
+* To add a new message to the database, we need to use the HTTP ``POST`` method. In the ``request.open`` method, pass in ``"POST"`` as the first parameter, and the Post endpoint as the second parameter. The endpoint to send a new message is ``/ids/:mygithubid/messages/``.  Refer back to the original [YouAreEll lab](https://git.zipcode.rocks/ZipCodeWilmington/YouAreEll) for documentation on the API if necessary.
548
+* For ``HTTP`` methods where a request ``body`` is necessary, pass the request body as a parameter to the ``request.send`` method. To send our ``message`` object as the ``request`` body, first convert it from a JavaScript object to a JSON object using the ``JSON.stringify`` method. 
549
+```javascript
550
+createNewMessage(message) {
551
+    const request = new XMLHttpRequest();
552
+
553
+    return new Promise(function (resolve, reject) {
554
+        // Setup our listener to process compeleted requests
555
+        request.onload = function () {
556
+            // Process the response
557
+            if (request.status >= 200 && request.status < 300) {
558
+                // If successful
559
+                resolve(JSON.parse(request.responseText));
560
+            } else {
561
+                reject({
562
+                    status: request.status,
563
+                    statusText: request.statusText
564
+                });
565
+            }
566
+        };
567
+
568
+        request.open("POST", `http://zipcode.rocks:8085/ids/${message.fromid}/messages`);
569
+
570
+        request.send(JSON.stringify(message));
571
+    });
572
+}
573
+```
574
+* Navigate to your ``index.js`` file. Notice that in our ``index.html`` file, we have a ``form``. This form exists to create and send new messages. In order to set up the form to listen to input from the user and respond propertly to the user hitting the submit button, we need to set up an ``eventListener`` for our form.
575
+* Create a new function in ``index.js`` called ``createFormListener``. This method takes 0 parameters.
576
+```javascript
577
+function createFormListener() {
578
+
579
+}
580
+```
581
+* Grab the ``form`` ``element`` using ``document.getElementById`` passing in the ``id`` of the ``form``.
582
+* Set the onsubmit property of the ``form`` to a function reference. This function takes one parameter, ``event``. This function will fire when the form is submitted.
583
+* To prevent the default form action from occuring, use the ``preventDefault`` method on the ``event`` object.
584
+```javascript
585
+function createFormListener() {
586
+    const form = document.getElementById("new-message-form");
587
+
588
+    form.onsubmit = function (event) {
589
+        // stop the regular form submission
590
+        event.preventDefault();
591
+    }
592
+};
593
+```
594
+* Navigate to ``index.html`` and find the ``form`` element. Notice that the ``form`` contains two form elements, ``textarea`` and ``button``. ``textarea`` has an ``attribute`` of ``name`` set to the property ``message``. When form elements are given a ``name`` ``attribute``, it adds information about that element the ``form`` object as a property.
595
+* Create a object called ``data`` with two properties, ``fromid`` and ``message``. ``fromid`` should be assigned the value of ``userid``, and message should be assigned the value of ``form.message.value`` (the value of the textarea with attribute ``name="message"``).
596
+* Call the ``createNewMessage`` method on the ``messageService`` object, passing in the ``data`` object. The ``createNewMessage`` method returns a ``Promise``, so specify your success and failure ``callbacks`` using the ``then`` method.
597
+* In your ``successCallback`` method, invoke the populateMessages
598
+```javascript
599
+function createFormListener() {
600
+    const form = document.getElementById("new-message-form");
601
+
602
+    form.onsubmit = function (event) {
603
+        // stop the regular form submission
604
+        event.preventDefault();
605
+
606
+        const data = {
607
+            fromid: userId,
608
+            message: form.message.value
609
+        };
610
+
611
+        messageService.createNewMessage(data)
612
+            .then(successCallback, errorCallback);
613
+
614
+        function successCallback(response) {
615
+            // This data comes from the resolve method
616
+            console.log(response);
617
+        }
618
+
619
+        function errorCallback(response) {
620
+            // This data comes from the reject method
621
+            console.log(response);
622
+        }
623
+    }
624
+};
625
+```
626
+### Part 8.0 - Adding Your New Message To the DOM
627
+
628
+* Just like we added our array of messages from before, we now need to add our new message to our list of messages.
629
+* Navigate to your ``index.js`` file. Add a method called ``addMessageToThread``. The method should take on parameter, a single ``message``.
630
+* Like before, we need to create a bunch of individual nodes and combine them together in order to create a full ``<li>`` element containing a message.  
631
+```javascript
632
+function addMessageToThread(message) {
633
+    const messageListItem = document.createElement("LI");
634
+    const userIdHeading = document.createElement("h3");
635
+    const messageParagraph = document.createElement("p");
636
+    const messageContent = document.createTextNode(message.message);
637
+    const userIdContent = document.createTextNode(message.fromid);
638
+    userIdHeading.appendChild(userIdContent);
639
+    messageParagraph.appendChild(messageContent);
640
+    messageListItem
641
+        .appendChild(userIdHeading)
642
+        .appendChild(messageParagraph);
643
+    messageList.appendChild(messageListItem);
644
+}
645
+```
646
+* Does this code look familiar? Before we move forward, let's go back and refactor our ``populateThread`` method to use this ``addMessageToThread`` method.
647
+```javascript
648
+function populateMessages(messages) {
649
+    messages.forEach(message => {
650
+        addMessageToThread(message);
651
+    })
652
+}
653
+```
654
+* Navigate back to your ``createFormListener`` method. In the ``successCallback``, invoke the ``addMessageToThread`` method, passing in the response, instead of logging the response.
655
+```javascript
656
+function createFormListener() {
657
+    const form = document.getElementById("new-message-form");
658
+
659
+    form.onsubmit = function (event) {
660
+        // stop the regular form submission
661
+        event.preventDefault();
662
+
663
+        const data = {
664
+            fromid: userId,
665
+            message: form.message.value
666
+        };
667
+
668
+        messageService.createNewMessage(data)
669
+            .then(successCallback, errorCallback);
670
+
671
+        function successCallback(response) {
672
+            // This data comes from the resolve method
673
+            addMessageToThread(response);
674
+        }
675
+
676
+        function errorCallback(response) {
677
+            // This data comes from the reject method
678
+            console.log(response);
679
+        }
680
+    }
681
+};
682
+```