Translate

Поиск по этому блогу

Показаны сообщения с ярлыком npm. Показать все сообщения
Показаны сообщения с ярлыком npm. Показать все сообщения

четверг, 9 июля 2020 г.

Как обновить npm на windows.

Сегодня мы разберем очень простую, на первый взгляд, но часто вызывающую вопросы, задачу - как правильно обновить npm (пакетный менеджер) на windows.



Очень часто проблема возникает, казалось бы ниоткуда, например: перестает правильно устанавливаться приложение create-react-app после его обновления или не устанавливаются какие-либо пакеты.

Если вы сталкивались с проблемой установки и запуска приложения React после обновления, используя npx, то сегодня мы найдем самое простое решение.

Первое, что нам нужно сделать это:

Запустить Windows PowerShell от имени администратора.

Я буду показывать на своем windows 8.1 (64 bit), но это мало будет отличаться от других версий (7 и 10). Чтобы открыть эту оболочку - Windows PowerShell, нам нужно нажать правой кнопкой мышки на окошко виндовс - ⊞ ( слева внизу - первое в трее) и выбрать, в появившемся списке - "Запустить Windows PowerShell от имени администратора". Обратите внимание, что именно Windows PowerShell, а не КС- командную строку(!!!)

Если этой команды нет в списке, как у меня, то просто нажимаем кнопку "Windows" - ⊞ Win (между левым Ctrl и Alt) и ищем в разделе "Приложения" => "Служебные - Windows" => Windows PowerShell



Как только вы нашли Windows PowerShell, то нужно нажать на нее правой кнопкой мышки и в выпадающем списке выбрать - "Запустить от имени администратора"



После этого сразу откроется окно Windows PowerShell и первое, что нам нужно сделать, это позволить исполнятся нужному сценарию. Для этого нужно ввести:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force


Более подробно о этом вы можете прочитать в статье Роберта Шелдона - Защита сценариев PowerShell

Теперь нам нужно исполнить само обновление - поочередно ввести вот эти две команды:

npm install --global --production npm-windows-upgrade
npm-windows-upgrade


Если вы просто хотите обновить npm до последней версии, то команда такая:

npm-windows-upgrade --npm-version latest


После этого ваш пакетный менеджер обновится и это избавит вас от многих неприятностей при установке пакетов и работе с приложениями.

Если для запуска новой версии create-react-app, вам не помогло обновление пакетного менеджера, то я настоятельно рекомендую вам прочитать мою статью о том, как исправить эти проблемы:Что нового в приложении Create React App 3

Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook. Пишите мне - kolesnikovy70 почта gmail.com


Удачного кодирования!                                                                                                                                                              

Телеграм канал - Full Stack JavaScript Developer
Помочь проекту (любая валюта). DONATE

суббота, 6 октября 2018 г.

Блог на NodeJS Express MongoDB ( III ).

Добавление постов - админ панель

Начать следует с добавления постов в блог. Для этого нам потребуется некая форма, которая будет принимать информацию от пользователя, обрабатывать ее и передавать на хранение в БД.



Все материалы по ES6


Добавление формы поста

Кнопка

На сайте Materialize возьмем кнопку.

Копируем код кнопки и добавляем в самый конец файла index.html.

Все что внутри тега ul удалим вместе с тегом. Это нам не нужно. Нам достаточно одной кнопки.



По ней сложно кликнуть, ничего не происходит. Поэтому надо поставит модальное окно.

Идем на сайт Materialize и там нам нужно посмотреть как работают модальные окна.

Берем modal-trigger и добавляем к ссылке нашей кнопки и далее нам нужно указать название модального окна, которое нам нужно открыть. Мы это будем делать через data-target="название"

Модальное окно

Так же берем с сайта Materialize готовый код окна и вставляем после кнопки.

Исправляем id - оно должно совпадать с значением data-target="createForm". Название поставим - "Создать новый пост", а вместо контента поставим поля ввода.

Файл index.html полностью


<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 <!-- Compiled and minified CSS -->
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"> 
 <!--Import Google Icon Font-->
 <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
 <title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
 <div class="container center" style="padding-top: 50px;">
  <div class="row">
   <div class="col s12 m8 offset-m2 lg6 offset-3" id="posts">
    <div class="preloader-wrapper small active">
     <div class="spinner-layer spinner-green-only">
      <div class="circle-clipper left">
       <div class="circle"></div>
      </div><div class="gap-patch">
       <div class="circle"></div>
      </div><div class="circle-clipper right">
       <div class="circle"></div>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
 <!-- button -->
 <div class="fixed-action-btn">
  <a class="btn-floating btn-large red modal-trigger" data-target="createForm">
   <i class="large material-icons">add</i>
  </a>
 </div>
   <!-- Modal Structure -->
  <div id="createForm" class="modal">
   <div class="modal-content">
    <h4>Создать новый пост</h4>
    <div class="input-field">
     <input id="title" type="text" class="validate" required>
     <label for="title">Название.</label>
    </div>

    <div class="input-field">
     <textarea id="text" class="materialize-textarea"></textarea>
     <label for="text">Название.</label>
    </div>
   </div>
    <div class="modal-footer">
      <a class="waves-effect waves-light btn" id="createPost">Создать пост.</a>
    </div>
  </div>

 <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
 <script src="index.js"></script>
</body>
</html>



Теперь нужно проинициализировать модальное окно

На нужно передать в глобальный объект Материалайза элемент, который нам нужно проинициализировать и после этого все должно работать.

M.Modal.init(elems, options);

Поэтому идем в скрипт - index.js

Уберем за одно и таймаут. Он нам уже не нужен.

Инициализируем модальное окно.

M.Modal.init(document.querySelector('.modal'))

внутри события загрузки всего документа.

Создаем глобальную переменную modal вверху файла и занесем в нее инстанс модального окна внизу, чтобы в последствии им можно было управлять.

Файл index.js


const card = post => {
 return `
    <div class="card z-depth-4">
         <div class="card-content">
           <span class="card-title">${post.title}</span>
           <p>${post.text}</p>
           <small>${post.date}</small>
         </div>
         <div class="card-action">
      <button class="btn btn-small red">
       <i class="material-icons">Delete</i>
      </button> 
         </div>
       </div>
 `
}

const BASE_URL = '/api/post'
let posts =[]
let modal;
class PostApi {
 static fetch(){
  return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
 }
}

document.addEventListener('DOMContentLoaded', () => {
 PostApi.fetch().then(backendPosts => {
  posts = backendPosts.concat()
  renderPosts(posts)  
 })
 modal = M.Modal.init(document.querySelector('.modal'))
})

function renderPosts(_posts=[]) {
 const $posts = document.querySelector('#posts')
 if(_posts.length > 0) {
  $posts.innerHTML = _posts.map(post=> card(post)).join()  
 } else {
  $posts.innerHTML = `<div class="center">Постов пока нет.</div>`
 }
}



Проверяем.



Придаем функциональность

Первое, что нам нужно сделать, это поставить прослушку события на кнопку в модальном окне. Когда мы кликаем по кнопке "Создать пост" мы будем вызывать функцию.

Внутри основного события загрузки документа в файле index.js возьмем кнопку -

document.querySelector('#createPost').addEventListener('click', onCreatePost)

Функцию мы вызываем без круглых скобок - просто передаем название.

Создаем функцию onCreatePost

В ней мы должны получит контент, который написан в инпутах. Посему, создадим переменные

$title = document.querySelector('#title')
$text = document.querySelector('#text')


Проверим, что эти поля не пустые:

if ($title.value && $text.value)

Если они не пустые, то нам нужно отправить POST-запрос, который мы реализовывали на сервере.

Для этого создадим date, которую мы хотим отправить на сервер. На сервере мы ожидаем увидеть два поля - title и text с запросом.

Поэтому мы здесь создадим новую переменную - newPost


  const newPost = {
   title: $title.value 
   text: $text.value
  }


И теперь когда у нас есть данные которые мы принимаем на сервере (объект) нам нужно отправить запрос.

Для этого у нас есть вспомогательный класс PostApi и давайте здесь же реализуем метод, который нам позволит создавать посты.

 static create(post) {

 }
Будет принимать объект поста.

Далее мы будем возвращать результат работы метода fetch(BASE_URL) по BASE_URL и далее нам необходимо передать объект конфигурации {}

Во первых мы ожидаем, что будем отправлять метод POST, поэтому


 static create(post) {
  return fetch(BASE_URL, {
   method: 'post',
  })
 }



Далее нам необходимо указать body (посмотрите на сервер - title: req.body.title, text: req.body.text, (14 и 15 строка файла routes/post.js)

Поэтому в методе fetch() мы так и пишем body и далее нам необходимо сделать строкой - сериализовать объект post

Сделаем так:

JSON.stringify(post)

Так же нам нужно здесь реализовать хедеры, чтобы сервер понимал, что работа идет с JSON-ом.


   hraders: {
    'Accept': 'application/json',
    'Content-Type':'application/json'
   }



Конфигурация запроса на этом закончена и после того, как пройдет метод fetch мф хотим получить некоторый body. Для этого в методу .then(res => res.json()) делаем то, что обычно с запросом. Отдаем некоторый json.

Метод create готов.


class PostApi {
 static fetch() {
  return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
 }
 static create(post) {
  return fetch(BASE_URL, {
   method: 'post',
   body: JSON.stringify(post),
   hraders: {
    'Accept': 'application/json',
    'Content-Type':'application/json'
   }
  }).then(res => res.json())
 }
}



Теперь у нас метод create готов и мы можем продолжить работу.

В функции onCreatePost мы сформировали новый пост и далее можем обратиться к классу PostAPI и с помощью метода create() передать ему данные - newPost и далее, когда обработается запрос и сервер нам ответит, в метод .then() мы получим новый объект post.

Нам нужно отобразить его в списке всех постов. Для этого у нас есть локальная переменная posts, гд хранятся все посты. Мы просто добавим его туда методом push()

И далее. чтобы отобразить новые посты, мы вызываем метод renderPosts(posts) c массивом posts.

Помимо того. что мы создали пост на сервере нам нужно сразу закрыть модальное окно -

modal.close()

И очистим значения инпутов -

$title.value = ''
$text.value = ''


И обновим текстовые инпуты - Обратиться к библиотеке материолайз и вызвать метод

M.updateTextFields() - по новому отобразит текстовые инпуты.

Сейчас при попытке создания посты мы получим следующее сообщение:



Для правильной работы нашего сервера нам нужно добавить плагин, который будет за нас парсить входящие данные. Мы с клиента их сериализовали - превратили в строку и теперь нужно сделать так, чтобы сервер их принимал как обычный JS-объект.

Для этого нам потребуется пакет body-parser

Остановим выполнение сервера.

Установим пакет, который автоматически будет парсить за нас входящие данные.

npm install body-parser


Подключаем его в папке app.js где-нибудь вверху.

const bodyParser = require('body-parser')

Теперь нужно применить пакет к нашему серверу.

Например. пред тем, как мы определяем роуты мы можем написать такую конструкцию:

app.use(bodyParser.json())

Будет преобразовывать входящие параметры в json-объект.

app.js


const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const path = require('path')
const postRouter = require('./routes/post')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
   .then(() => console.log('MongoDB connected'))
   .catch(err => console.error(err)) 
const app = express()
app.use(bodyParser.json())
app.use('/api/post', postRouter)
app.use(express.static(clientPath))
app.listen(port,()=>{
 console.log(`Server run on ${port} port`)
})



Запускаем сервер

Добавляем пост:



Если обновить страницу, то мы все равно увиим данный пост, потому что он берется уже из БД. В консоли можно посмотреть данные поста



Если посмотреть в mLab в коллекциях то мы увидим данные нашего поста.



Теперь можно добавлять посты на страницу.

Мы реализовали функционал по фетчингу и добавлению постов. осталось добавить удаление поста и правильный вывод даты, а так же сохранить форматирование строк поста.

Реализация удаления поста.

Нас интересует клиентский скрипт - index.js

Здесь есть функция, которая вызывается когда полностью загрузится контент DOM. В ней у нас уже есть прослушка событий на кнопке "Добавить пост". Создадим еще одну, которая позволит нам удалять определенные посты. В данном случае мы будем делегировать события и прослушку повесим на весь cписок постов (id="posts"), потому что на кнопку удаления повесить ее мы не можем, так как они все время меняются. Поэтому лучше делегировать события.

document.querySelector('#posts').addEventListener('click', onDeletePost)

и создаем данную функцию внизу файла.

В нее принимаем некоторый event

Теперь нам нужно определить, что нам нужно что-то удалить. Так как сейчас событие event будет срабатывать при клике по любому месту поста.

Нам нужно понять, что клик был именно по кнопке удаления поста.

Для этого мы можем в функции, которая генерирует нам html-карточки добавить на кнопку удаления поста специальный класс, напрмер .js-remove

Теперь нужно в функции определить, есть ли у элемента по которому мы кликнули этот класс.

В конструкцию if запишем: если у event.target в объекте classList есть класс .js-remove, то мы что-то делаем.

if (event.target.classList.contains('js-remove'))

далее спросим у пользователя через функцию confirm желает ли он удалить этот пост.

const decision = confirm('Вы уверены, что хотите удалить пост?')

А далее если пользователь нажал (согласился), то нужно понять какой именно пост нужно удалить.

Нам для этого нужно получить id поста. id хранится в объекте post._id. И зная что мы будем кликать именно по кнопке удаления, мы можем на кнопку добавить атрибут - data-id="${post._id}" и будем забирать именно этот атрибут.

const id = event.target.getAttribute('data-id')

Далее, зная нужный id мы можем отправить его на сервер.

Для этого нам нужно реализовать функцию удаления в классе PostApi.

Там мы создадим новую функцию static remove(id) в нее мы будем получать id и все что мы будем делать - возвращать функцию fetch() по BASE_URL но к нему надо еще добавить id, поэтому В параметрах метод delete, потому что мы будем слушать именно его. и после этого получим результат.


 static remove(id) {
   return fetch(`${BASE_URL}/${id}`, {
    method: 'delete'
   }).then(res => res.json())
 }



Теперь мы можем обратиться к классе PostApi взывать у него метод remove передать ему нужный id и как только сервер ответи успехом, мы в функции .then() удалим пост из списков (визуально)


function onDeletePost(event) {
 if (event.target.classList.contains('js-remove')) {
  const decision = confirm('Вы уверены, что хотите удалить пост?')

  if (decision) {
   const id = event.target.getAttribute('data-id')

   PostApi.remove(id).then(() => {
    const postIndex = post.findIndex(post => post._id === id)
    posts.splice(postIndex, 1)
    renderPosts(posts)
   })
  }
 }
}



Правильно указать дату поста и мультимтрочный текст

Текст.
Параграфу просто добавить инлайн стиль white-space:pre-line



Для нормального отображения даты нужно поле ${post.date} обернуть в конструктор ${new Date(post.date).toLocaleDateString()}

Метод приводит даты к локальному формату.

В итоге мы получили мини блог с адаптивным дизайном, возможностью сохранения в БД, удалением и созданием постов.





                                                                                                                                                             

четверг, 4 октября 2018 г.

Блог на NodeJS Express MongoDB ( II ).





Все материалы по ES6


Создание REST API роутов

В корне проекта создадим папку - routes.

Внутри нее создадим файл, который будет отвечать за роуты к постам - post.js

В файле сразу подключаем express - const express = require('express')

Далее создадим переменную, которая добывается из функции экспресс - Router()

const router = express.Router()

С этой переменной мы будем работать в этом файле и в конце экспортировать на ружу.

module.exports = router

Пока мы не пишем здесь никакого функционала. Давайте попробуем его применить для нашего сервера.

Для этого мы должны перейти в файл app.js, где мы описываем сервер и подключит данный роутер.

const postRouter = require('./routes/post.js').


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const postRouter = require('./routes/post')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
			.then(() => console.log('MongoDB connected'))
			.catch(err => console.error(err))	
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Теперь, для того чтобы использовать наш роутер, мы должны, после того, как определили объект нашего приложения =>const app = express() (ниже) написать команду

app.use('', postRouter)

Для того чтобы применить какой то роут и экспресc понимал ссылки.

Первым параметром мы можем указать url- префикс, который будет доступен для данного роута.

Вторым- тот роутер, который нам нужно использовать.

Теперь нужно подумать какой префикс нам здесь написать?

По сути, у нас будет часть сервера, которая будет отдавать клиентскую сторону - index.html и у нас будет часть сервера, которая будет отвечать за REST API. Соответственно, все что будет делаться через REST API мы можем начинать с префикса /api/ и далее, так как у нас идет здесь идет работа именно с постами, мы можем указывать сущьности - например post

app.use('/api/post', postRouter)

Теперь давайте разберемся как это будет выглядеть. Полная ссылка получения данных поста.

Перейдем в файл post.js

По сути для нашего приложения важно реализовать три действия:
  1. - получит все посты, которые есть в БД
  2. - создать новый пост
  3. - реализовать удаление какого-то поста
В REST API для того, чтобы получать что-то мы используем http-запросы с методом get.

Для того, чтобы реализовать метод get в экспрессе мы обращаемся к роутеру (router) и вызываем у него метод get.

Здесь в качестве параметра мы просто указываем слэш - '/'.

Вторым параметром указываем callback-функцию, которая принимает два параметра ( req -request - запрос res - response - ответ.)

Таким образом мы сможем манипулировать этими двумя вещами, когда будет приходить роут.


router.get('', (req, res) => {
	
})



Теперь давайте посмотрим. что это будет за роут и как он будет определяться.

У нас есть некоторый префикс - '/api/post' и это означает, что мы будем видеть запрос следующего характера:

http://localhost:5000/api/post

который будет реагировать на тип GET. И в случае, если экспресс увидит, что это запрос GET, то будет нам что-то отдавать.

Похожая ситуация у нас будет реализована еще для двух методов.

В REST API если мы хотим что-то создать, то мы используем метод POST, удалить - DELETE.

По сути, все запросы будут идти по одной и той же ссылке, но Экспресс будет понимать, что надо делать.

routes/post.js


const express = require('express')

const router = express.Router()
// http://localhost:5000/api/post GET
router.get('', (req, res) => {

})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Сейчас, давайте попробуем описать метод GET с помощью которого мы хотим что-то получить.

Для этого изначально нам нужно подключить саму модель, которую мы создавали ранее.

const Post = require('../models/Post')

Теперь с помощью этого объекта мы уже можем работать с БД.

Для того, чтобы получить все сущьности из БД, нам нужно в методе GETобратиться к и вызвать у него метод find(), передав в метод пустой объект. Это означает, что мы будем требовать все посты без каких либо условий.


router.get('', (req, res) => {
	Post.find({})
})



Данная операция является асинхронной. Она нам будет возвращать некий промис мы его можем ченить с помощью метода .then и после этого как-то обрабатывать.


router.get('', (req, res) => {
	Post.find({}).then((posts)=>{
 	//что-то делать...	
 })
})



Мы пойдем более современным путем. Так как мы работает на платформе NodeJS, которая не требует понимания разных браузеров, то здесь можно использовать все новшества современного JS ES6.

Поэтому мы смело можем использовать синтаксис - async/await.

Вместо того, чтоб так ченить промисы.

Мы можем сказать NodeJS, что данная функция будет являться асинхронной и поставить вначале нее async

И теперь, чтобы получить список этих постов, мы можем просто создать переменную posts и с помощью префикса await - подождать.

const posts = await Post.find({})

Эта конструкция полностью идентична

	Post.find({}).then((posts)=>{
          // ...
	})



При этом мы написали полностью асинхронный код и у нас нет вложенных функций.

Таким образом мы получили:


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
const posts = await Post.find({})
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Думаем над тем. что нам делать еще в методе GET По сути, мы должны что-то отдать клиенту (список постов). Для того, чтобы ответить клиенту мы можем воспользоваться объектом res, затем указать статус

res.status(200) и с помощью метода json указать те данные, которые мы хотим отправить обратно - posts.

res.status(200).json(posts)


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('', async(req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('', (req, res) => {
	
})
// http://localhost:5000/api/post DELETE
router.delete('', (req, res) => {
	
})

module.exports = router



Коротко: мы просто ждем, что сто-то придет к нам с базы данных и после этого отправляем их клиенту.

Метод POST

Здесь мы должны сформировать новый пост в зависимости от тех данных, которые к нам придут.

Создадим переменную postData и это будет объект с полями title и text. Здесь мы будем с клиента отправлять данные в БД. Для сбора данных и нужны эти поля.

Теперь эти данные нужно обработать. Это сделать просто. У нас есть объект req с помощью которого будет сделан запрос и сказать ему, что например, title хранится в req.body.title.


router.post('', (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
})



Теперь у нас есть данные необходимые для создания нового поста в базе и мы можем создать новый пост с помощью модели Post на основе данных postData.

const post = new Post(postData)

И после этого нам нужно сохранить это все в БД. Для этого можно просто написать:

await post.save()

И сделать функцию асинхронной:


router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
})



Этой строкой -

await post.save()

мы будем ждать, когда код сохранится на сервере. Далее объект post изменится, потому что придет ответ с БД и у нас будет уникальный ID, который нам выдаст MongoDB и у нас определится дата. когда был создан пост..

И теперь мы можем ответить (res)клиенту оперируя теми данными, которые мы получили с БД.

В RESTAPI если мы что-то создаем, то используем статус 201, а далее методом json мы указываем. чо будем обратно возвращать post.

res.status(201).json(post)


// http://localhost:5000/api/post POST
router.post('', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})



Метод DELETE

Он будет тоже асинхронным, как и предыдущие методы. (Добавим async).

В этом методе нам нужно будет удалить пост по ID. Поэтому здесь уже не подойдет такой url - http://localhost:5000/api/post, потому что нам в нем надо передать id того поста, который мы хотим удалить. Например id =34;

http://localhost:5000/api/post/34

Эта часть будет динамическая.

Для того, чтобы указать какую-либо динамическую часть в Экспрессе, нам достаточно поставить после слэша двоеточие и написать id.

Именно так - id будет называться параметр, который мы будем получать в этом месте.

Теперь нам нужно с помощью модели Post вызвать метод remove(), который позволяет нам что-то удалять из базы. и далее мы говорим условия - какой именно пост мы хотим удалить в объекте. Мы хотим удалить пост у которого _id === id который придет в роуте. А этот параметр хронися в объекте запроса req (req.params.is)

Так как функция асинхронная, то мы ее должны подождать - await


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
})



Как только удалится нужный нам пост мы можем ответить клиенту статусом 200 и в json отправить мессендж -"Удалено"


router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})



Теперь наш роутер, который работает с сущностями поста полностью готов.

Файл post.js


const express = require('express')

const router = express.Router()

const Post = require('../models/Post')
// http://localhost:5000/api/post GET
router.get('/', async (req, res) => {
	const posts = await Post.find({})
	res.status(200).json(posts)
})
// http://localhost:5000/api/post POST
router.post('/', async (req, res) => {
	const postData = {
		title: req.body.title,
		text: req.body.text,
	}
	const post = new Post(postData)
	await post.save()
	res.status(201).json(post)
})
// http://localhost:5000/api/post DELETE
router.delete('/:id', async (req, res) => {
	await Post.remove({_id: req.params.id})
	 res.status(200).json({
	 	message: 'Удалено'
	 })
})

module.exports = router



Далее перейдем к тестированию, создав некую клиентскую часть.

Тестирование серверной части.

Всё, что относится к фронтенд части хранится в папке client. Там, пока что, один файл - index.html

Начнем с верстки. На ней я подробно останавливаться не буду. Отмечу только, что для адаптивности и простоты я использовал фреймворк Materialize.

Подключаем css, material icons и скрипт js к нашему index.html файлу через CDN (ссылки на сайте) . После скрипта материалайза подключаем наш скрипт index.js, который мы создадим в той же папке.

В нем мы будем вести разработку на нативном JS.

В файле index.html создадим div - контейнер, которому зададим стиль, чтобы он не прилипал к верху экрана и в него мы будем выводить посты.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="post">
				<div class="card">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



Запускаем сервер

npm run dev


Переходим на сайт localhost:5000 и видим:



Теперь перейдем к клиентскому скрипту и посмотрим как вывести список всех постов.

Первое - нам нужно сделать некий компонент, который будет генерировать html-код определенного поста. Поэтому, все что отмечено красным вырезаем и переносим в файл index.js


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="post">
		<div class="card z-depth-4">
	        <div class="card-content">
	          <span class="card-title">Post Title</span>
	          <p>I am a very simple card. I am good at containing small bits of information.</p>
	          <small>12.12.1212</small>
	        </div>
	        <div class="card-action">
						<button class="btn btn-small red">
							<i class="material-icons">Delete</i>
						</button>	
	        </div>
	      </div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



И так как здесь у нас нативный JS, то мы создадим подобие компонента в переменной card


const card = post => {
	return `
		<div class="card z-depth-4">
	           <div class="card-content">
	            <span class="card-title">${post.title}</span>
	            <p>${post.text}</p>
	            <small>${post.date}</small>
	           </div>
	          <div class="card-action">
		    <button class="btn btn-small red">
			<i class="material-icons">Delete</i>
		    </button>	
	        </div>
	      </div>
	`
}



Функция, которая принимает post и отдает html разметку. Данные в которой мы выводим как переменные.

Теперь нам нужно сделать запрос на backend и убедиться, что мы получаем список всех постов.

Для этого нам потребуется некоторый инструмент с помощью которого мы будем делать запросы.

Так как мы сейчас работаем с постами, то мы можем создать локальный класс, который будет отвечать за запросы к бэкенду.

Допустим, что это будет класс PostApi. У него будет несколько методов.

Первый статический static fetch(), в который мы не будем передавать параметры. Этим методом мы будем делать запрос на получение всех наших постов.

В JS есть нативная функция fetch(), с помощью нее мы как раз и можем делать запросы.

Первым параметром в эту функцию нам надо передать url по которому мы хотим сделать запрос.

Для этого мы создадим новую константу - const BASE_URL='api/post' - Это та самая строчка. которая обозначена в файле app.js.

Вторым параметром мы указываем метод с помощью которого мы хотим сделать запрос. В нашем случае, когда мы хотим получить список всех потов это метод GET. ({method: get}.

Далее, метод fetch() возвращает промис и в методе .then мы можем привести тот формат который прилетает к нам с сервера и обрабатывается JS, привести в понятный формат объектов. Поэтому - res=>res.json() и все это вернем из метода fetch().


const BASE_URL = '/api/post'

clss PostApi {
	static fetch(){
		return fetch(BASE_URL, {method: get}).then(res=>res.json())
	}
}



И теперь в какой момент нам необходимо сделать запрос?

При загрузке страницы.

На документ поставим обработчик события.

document.addEventListener('DOMContentLoaded', () => {
	
})


Как только запускаем приложение нам нужно сделать запрос к бекенду, поэтому мы обращаемся к PostApi.fetch и вызываем метод .fetch() и так как он возвращает промис, то .then(). В этом методу мы будем получать объект backendPosts. То есть это будет уже тот массив, который прилетит от сервера. И теперь, нам нужно просто вывести все эти посты в html.

Для этого создадим наверху файла переменную let posts = []. Именно в ней мы будем хранить все посты, которые у нас есть.

Когда мы получим наши посты то в эту переменную мы положим содержимое backendPosts на котором вызовем метод concat, для предотвращения проблем мутаций.

Он просто сгенерирует дубликат данного массива.


const BASE_URL = '/api/post'
let posts =[]
clss PostApi {
	static fetch(){
		return fetch(BASE_URL, {method: 'get'}).then(res=>res.json())
	}
}

document.addEventListener('DOMContentLoaded', () => {
	PostApi.fetch().then(backendPosts => {
		posts = backendPosts.concat()
	})
})



Теперь, когда у нас есть список всех постов с бэкенда и нам остается их отрендерить.

Для этого создадим функцию renderPosts(posts) куда и передадим эти посты.

Функцию опишем ниже. По умолчанию она будет принимать пустой массив - _posts=[]

У нас есть id="posts" в файле index.html куда нам нужно выводить наши посты.

$ - просто обозначает, что это некоторый элемент.


function renderPosts(_posts=[]) {
	const $posts = document.querySelector('#posts')

}



Далее, проверим. Если длина массива пришедшего в функция больше 0, то есть у нас есть некоторые посты, то мы будем генерировать карточки. Иначе мы просто выведем сообщение "Постов пока нет".

Если посты есть, то мы должны сгенерировать html. Нам нужно пробежаться по массиву постов и сформировать из каждого карточку с нужным html.

Мы можем обратиться к локальной переменной _posts и далее с помощью метода .map() мы на каждой итерации будем получать определенный post (это объект) и на выходе вернуть html, то есть вызвать функцию card(post)

Преобразуем массив к строке методом .join(' '). Через пробел.


function renderPosts(_posts=[]) {
	const $posts = document.querySelector('#posts')
	if(_posts.length > 0) {
		$posts.innerHTML = _posts.map(post=> card(post)).join()	 
	} else {
		$posts.innerHTML = `
Постов пока нет.
` } }


Сохраняем и обновляем страницу Идем на вкладку Networkв в консоли.



Видим, что "Постов пока нет", а в запросах - url совпадает и метод GET, и получаем пустой массив post



С выводом постов мы разобрались.

Единственное что мы можем добавить, это индикатор загрузки.

Имитируем задержку сервера функцией setTimeout пред рендерингом постов, а на это время сделаем показ индикатора загрузки.


document.addEventListener('DOMContentLoaded', () => {
	PostApi.fetch().then(backendPosts => {
		posts = backendPosts.concat()
		setTimeout(()=>{
		renderPosts(posts)
		}, 2000)			
	})
})



Прелоудер возьмем на сайте materializecss.com

Скопируем там готовый код прелоудера и добавим его в наш див поста в файле index.html

Файл index.html полностью:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	 <!-- Compiled and minified CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">	
  <!--Import Google Icon Font-->
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<div class="container center" style="padding-top: 50px;">
		<div class="row">
			<div class="col s12 m8 offset-m2 lg6 offset-3" id="posts">
				<div class="preloader-wrapper small active">
					<div class="spinner-layer spinner-green-only">
						<div class="circle-clipper left">
							<div class="circle"></div>
						</div><div class="gap-patch">
							<div class="circle"></div>
						</div><div class="circle-clipper right">
							<div class="circle"></div>
						</div>
					</div>
				</div>
			</div>
		</div>
	</div>


	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="index.js"></script>
</body>
</html>



Файл index.js полностью:



const card = post => { return ` <div class="card z-depth-4"> <div class="card-content"> <span class="card-title">${post.title}</span> <p>${post.text}</p> <small>${post.date}</small> </div> <div class="card-action"> <button class="btn btn-small red"> <i class="material-icons">Delete</i> </button> </div> </div> ` } const BASE_URL = '/api/post' let posts =[] class PostApi { static fetch(){ return fetch(BASE_URL, {method: 'get'}).then(res=>res.json()) } } document.addEventListener('DOMContentLoaded', () => { PostApi.fetch().then(backendPosts => { posts = backendPosts.concat() setTimeout(()=>{ renderPosts(posts) }, 2000) }) }) function renderPosts(_posts=[]) { const $posts = document.querySelector('#posts') if(_posts.length > 0) { $posts.innerHTML = _posts.map(post=> card(post)).join() } else { $posts.innerHTML = `<div class="center">Постов пока нет.</div>` } }


Теперь перед загрузкой постов мы будем видеть индикатор - вращающиеся полуокружность и через 2 сек. сообщение "Постов пока нет".





                                                                                                                                                             

среда, 3 октября 2018 г.

Блог на NodeJS Express MongoDB ( I ).

С этого поста начинаем разработку блога с использованием fullstack - технологий.



Все материалы по ES6




Самое простое объяснение, что такое fullstack - разработка клиентской и серверной частей. Разработка идет двух этих сущностей независимо друг от друга, а потом мы их связываем в единый блок.

В этих трех постах мы создадим блог, где мы сможем создавать посты, выводить их и удалять.

Сервер мы напишем на NodeJS с использованием фреймворка Express. Плюс, мы будем связываться с фронтэндом, который будет написан на нативном JavaScript через REST.API

  1. Создадим папку нашего проекта. Я создал папку - fs-blog.


  2. Нам потребуется установленная NodeJS.

    Проверить очень просто. В КС (здесь и далее - командная строка) нужно ввести:

    node -v


    Enter

    Если NodeJS установлена, то уведите ее версию, а если нет, то ее стоит установить с официального сайта. Это очень просто и я останавливаться на этом не буду.


  3. Инициализация проекта.

    Эту необходимо сделать для автоматической генерации файла package.json, где будут храниться все зависимости нашего проекта.

    Переходим в КС в папку проекта. Для этого можно использовать команду

    cd NameFolder


    Можно просто перетащить папку в КС и получить путь, можно начать вводить имя папки и нажать Tab.

    После того, как вы оказались в папке проекта, в КС вводите:

    npm init


    Здесь мы можем ввести необходимые данные в файл package.json - зависимости и настройки нашего проекта.

    Можно добавить описание - description: simple blog

    entry point - это основной файл (точка входа в проект). Я укажу app.js

    keywords: blog, node.js, fullstack

    Avtor: Your Name

    y

    Enter

    Теперь в корне проекта мы получим файл package.json где хранятся все данные, которые мы добавляли через КС.


  4. Создание точки входа app.js

    В этом файле мы будем вести разработку нашего сервера.


  5. Устанавливаем фреймворк Express.


npm install express


В современных npm версиях указывать флаг --save не нужно. Зависимости и так пропишутся автоматически в файле package.json.

Если посмотреть, то в файле package.json появится ваша версия "express" в разделе "dependencies"

В папке node_modules хранятся файлы библиотеки, и появится файл pachage-lock.json, который служит для разруливания различных зависимостей и версий пакетов. Его трогать не нужно. Он генерируется автоматически.

Создание и запуск сервера.

Давайте разберемся - с чего начинается разработка сервера на Express.

  1. - Нам нужно подключить сам Express к нашему проекту.

    const express = require('express')

    Создали одноименную фреймворку переменную, куда с помощью глобальной для Node.js функции require() положили фреймворк, а точнее содержимое папки express, которая находится в node_modules.Указываем не путь, а название пакета и NodeJSпонимает, что данный пакет нужно брать из папки node_modules.


  2. -создаем сервер в переменной, которая будет отвечать за наше приложение - app.

    const app = express()

    Таким образом мы получили объект app, который будет ключевым для нашего сервера.


  3. - для запуска сервера нужно указать Экспресу о том, что мы будем что-то слушать :-)


Создадим переменную const port = 5000

Для запуска сервера нам нужно обратиться к объекту app, его методу listen()-с помощью этого метода мы можем запускать прослушку всего сервера. Первым параметром в этот метод мы передадим номер порта где мы хотим все это слушать ( наша переменная port). Вторым параметром - callback-функцию, которая будет вызвана, когда сервер заработает.

Для порта допишем функциональность. Обычно, мы можем передавать различные переменные, информацию через консоль в NodeJS и обычно порт передается через консоль, например, если мы будем куда-то выкладывать наш проект. Поэтому нам нужно проверить - если у нас указана системная переменная, которая содержит номер порта, тогда мы будем использовать её, а если нет, то порт 5000. Для того, чтобы в NodeJS обратиться к каким-то системным переменным, мы обращаемся к глобальному объекту process. У него есть объект environment (окружение) и название параметра, если он существует. А если его нет, то порт 5000:

const port = process.env.PORT || 5000

Таким образом мы получили файл app.js


const express = require('express')

const port = process.env.PORT || 5000

const app = express()

app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Запустим сервер:

node app.js


В консоли мы увидим Server run on 5000 port



Перейдем по адресу localhost:5000

Если мы увидим вот такое сообщение - Cannot GET /, значит сервер запущен и все работает правильно.



Давайте еще подготовим наше окружение для работы.

Переходим в файл package.json и напишем два скрипта в поле "scripts". Сейчас здесь есть один тестовый скрипт. Он нам не нужен и мы его удалим. Вместо него запишем скрипт, который будет запускать весь наш сервер:


  "scripts": {
    "start": "node app.js"
  },



Теперь в консоли (КС) мы можем для запуска приложения (сервера) написать команду:

npm run start


И нажать Enter.



Отдаем html-страницу.

В корне нашего проекта создадим папку, которая будет отвечать за клиентскую часть - client.

Внутри нее создадим файл - index.html.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	<title>FS-Blog</title>
   <!--[if IE]>
   <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 <![endif]-->
</head>
<body>
	<h1>FS-BLOG</h1>
</body>
</html>



Теперь нам нужно указать серверу, что при запросе на корневой роут, нам нужно запускать именно index.html

По сути - это сделать папку client публичной, статической. И когда мы будем делать запрос на сервер, то будем оказываться в папке client и по умолчанию отдавать файл index.html.

Для этого мы в файле арр подключим новый модуль path. Данный модуль входит в состав NodeJS и потому не требует дополнительной установки.

const path = require('path')

С помощью него можно очень удобно работать с разными путями.

Создадим новую переменную const clientPath, куда мы положим абсолютный путь до папки client. Воспользуемся методом join() модуля path.

В NodeJS есть глобальная переменная - __dirname, которая отвечает за абсолютный путь к текущей папке. Так, как мы сейчас в корневой папке нашего блока. то в __dirname мы получим абсолютный путь в папке fs-blog.

И чтобы теперь указать путь к папке client, нам нужно просто указать папку вторым параметром в методе join(). Вот так:

const clientPath = path.join(__dirname, 'client')

Теперь, когда мы получили путь до нужной нам папки, нам нужно сделать её статической.

Статической она делается довольно просто. После того, как мы с вами определим объект app, мы можем "оповестить" Экспресс о том. что хотим с помощью метода use(), добавить некий функционал серверу. Внутри метода указываем статическую, публичную папку. Для этого мы обращаемся к статическому методу экспреса и указываем путь до этой папки - clientPath:

app.use(express.static(clientPath))

Теперь, если мы будем делать запрос на сервер, он должен отдавать нам файл index.html.



Запуск рабочего процесса сервера - настройка окружения

Для остановки сервера нам приходится нажать Ctrl + C, потом ввест y и нажать Enter. Запуск его требует введения в КС:

npm run start


и опять Enter

Дело в том, что при внесении изменений в файлы, нам нужно постоянно перезапускать сервер, чтобы изменения вступили в силу (пересобрался сервер). делать это постоянно не очень удобно. Для того, чтобы сервер перезапускался автоматически после внесенных изменений мы установим пакет nodemon.

Чтобы его установить нам нужно ввести команду:

npm install nodemon -D


Enter

Здесь -D флаг, который указывает, что данная зависимость нужна нам только для разработки (development).

Проверим файл package.json. Там нас интересует поле


  "devDependencies": {
    "nodemon": "^1.18.4"
  }



Значит все прошло правильно. Остается только добавить еще один пользовательский скрипт в это файл:


  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js"
  },



Он будет делать тоже самое, что start но через пакет nodemon.

Теперь запуск сервера будет происходить командой:

npm run dev




База данных

Подключение MongoDB

Для этих целей нам потребуется локальный пакет mongoose, с помощью которого мы сможем делать очень удобные запросы к MongoDB. С помощью него мы сможем создавать модели, которые в последствии будут сущьностями в БД (база данных - здесь и далее.)

Установка пакета:

npm install mongoose


Есть разные возможности работы с БД - MongoDB. Можно её установить на компьютер локально. Плюсом такого подхода - это очень быстрое взаимодействие между сервером и БД. Минус - сложности установки MongoDB на комп. У всех разные системы, версии и пр. Для того, чтобы не отвлекаться на локальную установку, мы можем воспользоваться сервисом, который предоставляет полный API для MongoDB. Это сервис mLab.

Как можно предположить, это сервис который является удаленной версией MongoDB. Плюсы: простота использования, удобсвто настроек, бесплатно. Минусы - немного потеряем в скорости.

Нужно зарегистрироваться (создать аккаунт). Регистрация обычная. С подтверждением на почту.

Посте того, как залогинетесь появится окно с базами. Нам нужна кнопка - "Создать"



Выбираем Amazon и Бесплатную версию и нажимаем "Продолжить".



Выбрать точку поближе к себе на карте ( из предложеного и нажать "Продолжить"



Выбираем и вводим название:



Готовый чек - проверяем. Все действительно бесплатно и соглашаемся.



Происходит создание базы. Это может занять некоторое время и далее вы увидете:



База создана и готова к работе.

Переходим в нее (просто нажать на нее). и ...



Копируем эту строчку и возвращаемся в проект (редактор).

Давайте создадим некторую конфигурацию для наешего проекта, путем создания нового файла в корне приложения и назовем его keys.js

Здесь мы будем хранить некоторые константы, которые нужны для работы нашего приложения. Мы будем формировать здесь объект и экспортировать его наружу, чтобы другие файлы могли получать доступ к этим данным.


module.exports = {
	mongoURI: 'mongodb://<dbuser>:<dbpassword>@ds121413.mlab.com:21413/fs-blog'
}



Значением данного свойства мы вставили скопированную ссылку. В ней нам интересуют две вещи (отмечено красным).

Именно эти теги user и password нас интересуют.

Их нужно получить. В данном сервисе (mLab) нам нужно создать пользователя, который получит права доступа к БД. На записаь, на чтение и на удаление записей.

Выбираем "Users" "Add database user"



В сплывающем окне вводим имя и пароль. Галочку "read only" - НЕ СТАВИМ !

потому что мы хотим изменять базу данных

Данными имения и пароля мы заменяем теги user и password вместе с угловыми скобками.

После того, как мы получили ключи от БД мы идем в app.js и здесь мы подключаем mongoose


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



теперь в этом файле нам необходимо подключиться к MongoDB

Подключение к MongoDB.

Сделаем это после подключения констант. Для этого мы обращаемся к пакету mongoose и вызываем у него метод - connect(). Первым параметром нам нужно передать адрес БД к которой мы хотим подключиться. Для этого нам нужно подключить файл констант, подключить переменную keys из файла который лежит на одном уровне с файлом app.js, потому пишем './keys.js':

const keys = require('./keys')

.js можно не указывать, потому что NodeJS понимает, что по умолчанию это .js- файл.

Таким образом мы передаем первым параметром переменную keys.mongoURI

Метод connect() возвращает нам промис.

Мы можем использовать два метода .then() и .catch().

В случае успеха передадим в консоль 'MongoDB connected', а в случае неудачи выведем в консоль ошибку.


const express = require('express')
const mongoose = require('mongoose')
const path = require('path')
const keys = require('./keys')

const port = process.env.PORT || 5000
const clientPath = path.join(__dirname, 'client')

mongoose.connect(keys.mongoURI)
			.then(() => console.log('MongoDB connected'))
			.catch(err => console.error(err))	
const app = express()
app.use(express.static(clientPath))
app.listen(port,()=>{
	console.log(`Server run on ${port} port`)
})



Запустим сервер

npm run dev


и в консоли увидим:



Теперь нам предстоит создать модель, для того, чтобы определить некоторую сущность в БД.

Наше приложение это блог, и по сути, мы будем работать с постами.

В корне проекта создадим новую папку, которая будет отвечать только за модели models.

Файлы этой папки (модели) в NodeJS принято называть с заглавной буквы.

Для работы с постом. создадим файл, в этой папке - Post.js

Теперь нам нужно описать модель, то есть какие сущьности будут у определенной модели в БД для поста.

первое что мы будем делать - это подключим mongoose, потому что с помощью него мы и будем описывать это все.

И далее. как это принято в мангусе. Мы создаем определенную схему, описываем поля,типы, описываем дефолтные значения, и после этого мы регистрируем нужную нам модель.

Первый шаг - это создание схемы!

Создание схемы

. Создаем переменную Schema она определяется из переменной mongoose и у нее есть класс Schema.

const Schema = mongoose.Schema

Теперь мы создаем схему нашего поста то есть - описание модели. Назовем её postSchema, например.

Она является экземпляром класса Schema, где в конструктор мы передаем объект конфигурации.

Давайте решим. что у нашего поста может быть?


 const mongoose = require('mongoose')

 const Schema = mongoose.Schema

 const postSchema = new Schema({
 	
 })



Во-первых - уникальный id, но его будет выдавать сама БД (MongoDB), поэтому нам его описывать необязательно.

У поста будет название, текст и дата создания.

Начнем с описания названия поста. Допустим, что это будет title и это объект. Так как мы описываем схему.

Какого типа будет у нас заголовок? Мы описываем его как строку - String и говорим, что заголовок для каждого поста нам нужен обязательно :


 const postSchema = new Schema({
 	title: {
 		type: String,
 		required: true
 	}

 })



Далее описываем контент поста - точно так же.

Еще одно поле date - дата когда был создан пост. По сути, было бы логично, если бы сервер при создании поста сделал это за нас.

Тип переменной будет Date, потому что мы будем работать с датой. И так как сервер у нас будет сам выдавать дату создания, то вместо флага required - default

default: Date.now

Важно без скобок, чтобы не вызывать эту функцию.

С помощью метода мы экспортируем наружу данную модель и экспортируем мы результат регистрации данной модели в базе. То есть говорим mongoose о том, что с помощью метода model() мы хотим зарегистрировать в БД новую коллекцию - posts и модель каждого поста будет являться схемой которую мы создали.

module.exports = mongoose.model('posts', postSchema)

Файл Post.js


 const mongoose = require('mongoose')

 const Schema = mongoose.Schema

 const postSchema = new Schema({
 	title: {
 		type: String,
 		required: true
 	},
 	text: {
 		type: String,
 		required: true
 	},
 	date: {
 		type: Date,
 		default: Date.now
 	}

 })

 module.exports = mongoose.model('posts', postSchema)



База подключена и осталось разработать на сервере роуты, которые будут работать с разными постами.





                                                                                                                                                             

вторник, 2 октября 2018 г.

Основы Node JS & Express ( III ).

Основы Node JS & Express ( III ).

Разбираемся, что такое npm и для чего он нужен. Устанавливаем Express и шаблонизатор EJS. Делаем полную подготовительную работу и начинаем создавать свой собственный сайт на NodeJS.



Все материалы по JavaScript


Пакетный менеджер npm.

npm - это менеджер пакетов для JavaScript и крупнейший в мире реестр программного обеспечения.

Говоря простыми словами - это программное обеспечение, которое позволяет нам устанавливать различные библиотеки, зависимости между ними, подключать к нашему проекту различные дополнительные модули и выгружать свой собственный код в какой-либо репозиторий.

npm полностью бесплатный и скачивается вместе с установкой Node.JS.

Установить нужные пакеты или библиотеку очень просто. В поиск на сайте npm вводите название нужной библиотеки и получаете полное руководство по установке.

Для установки нужно в КС (командной строке) перейти в папку проекта и набрать:

npm install package_name


package_name - название пакета, или библиотеки.

Удалить:
npm uninstall package_name


Нажать Enter.

Файл package.json.

Когда вы работаете над проектом и захотите отправить свой код какому-либо другому программисту, то вам не нужно будет отправлять все библиотеки и модули, которые у вас есть в проекте. Это очень затратный процесс. Вы сможете отправить свой код без библиотек. В файле package.json будет вся информация по вашему проекту и зависимостях и любой разработчик сможет легко развернуть ваш проект на любой машине используя ту информацию, которая есть в файле package.json. Ему будет достаточно просто прописать в КС команду

npm install


И все библиотеки и зависимости будут автоматически установлены в проект.

Создание файла package.json

Для создания этого файла можно просто ввести в КС:

npm init


Далее можно заполнить предложенные строки, или просто нажимать Enter. В конце согласиться - нажать y и Enter.

После этого в папке проекта появится новый файл - package.json. Если его открыть, то вы увидите там все информацию по проекту.

Раздел dependencies служит для сохранения всех зависимостей нашего проекта.

Экспресс

Библиотека Express хороша по многим причинам. Она позволяет значительно упростить написание кода. Например: отслеживание url-адресов здесь будет настроено намного проще, нежели в NodeJS. Кроме того здесь есть различные шаблонизаторы, которые позволяют легко выводить html вместе с данными полученными от NodeJS.

Установка Express

Очень простая. Открываем папку нашего проекта в КС. Для этого достаточно просто перетащить туда папку, чтобы получить путь (фишка для windows).

npm install express -save


Флаг -save позволит сразу прописать эту библиотеку в зависимостях dependencies файла package.json.

Работа

чтобы обратиться к библиотеке мы создадим переменную и пропишем:

let express = require('express');

Теперь этот модуль вернет нам функцию, которую мы должны вызвать.

Создадим новую переменную app и обратившись к переменной express вызываем ее, как функцию.

let app = express();

Таким образом мы в переменной app получим доступ ко всем функциям, которые ест ьу нас в библиотеке Express - мы сможем подключиться к серверу, обрабатывать различные ссылки и пр.

Здесь мы точно так же настраиваем сервер и должны указать порт, который мы будем отслеживать.

app.listen(8080);

Маршрутизация в Express

Для отслеживания ссылок:

app.get() - отслеживает get запросы.

app.post()-отслеживает post запросы.

Так, как мы собираемся отслеживать get-запрос на нашу главную страницу. то пишем так:

app.get('/', fn)

fn - вторым параметром - функция, которая похоже на функцию, которая была в NodeJS ранее. У этой функции в Express больше возможностей.

Для начала, просто выведем текст, когда будем попадать на главную страницу.

res.send('This is Home');

.send() - в Express почти тоже самое, что .end() NodeJS.

index.js


let express = require('express');

let app = express();

app.get('', function(req, res){
	res.send('This is Home');
});

app.listen(8080);



В КС

node index.js




Вывели текст на страницу. Если попробовать перейти на др страницу, например http://localhost:8080/test,

то увидим:



Если бы мы прописали еще один обработчик:


let express = require('express');

let app = express();

app.get('/', function(req, res){
	res.send('This is Home');
});
app.get('/news', function(req, res){
	res.send('This is News');
});
app.listen(8080);





Выводить html текст здесь так же просто.

В данный момент мы умеем отслеживать только статические ссылки.

То есть эти ссылки никак не меняются.

А что если нам нужно отследить ссылку с каким то ID статьи? Например /news/23

Для этого нам нужно добавить еще один /: и абсолютно любое имя, которое мы захотим.

Например так:


app.get('/news/:id', function(req, res){
	res.send('This is News');
});



И теперь по этому id можно отслеживать ту часть, которая будет там записана. Мы можем даже вывести id на страницу.

req.params.id - здесь id - название отслеживаемого параметра. Оно будет любое, но точно такое как и /news/:id



В данном случае, id может быть строкой, числом и вообще всем чем угодно :-) Это не привязывает нас к числам!

Можно поменять id на name или любое другое.


app.get('/news/:name', function(req, res){
	res.send('ID is - ' + req.params.name);
});



По этому id мы можем брать информацию из базы данных и показывать (статью. фото и пр).

Отслеживать несколько параметров:


app.get('/news/:name/:id', function(req, res){
	res.send('ID is - ' + req.params.name + req.params.id);
});





Использование шаблонизатора.

Отображаем html-файлы в браузере

До этого мы использовали метод send(), теперь нам нужно использовать метод - sendFile(), которому мы должны передать путь к файлу.


let express = require('express');

let app = express();

app.get('/', function(req, res){
	res.sendFile(__dirname + '/index.html');
});
app.get('/about', function(req, res){
	res.sendFile(__dirname + '/view/about.html');
});
app.get('/news/:name/:id', function(req, res){
	res.send('ID is - ' + req.params.name + req.params.id);
});
app.listen(8080);



Файлы можно поместить в отдельную папку ( на примере about).

Файлы я взял из части второй этого курса. Если вы не знакомы с ней, то вот ссылка Основы NodeJS - Вторая часть.

Теперь с параметрами, которые постоянно будут меняться.

Если нам нужно создать ссылку на некое значение, после /mews/значение. Оно будет меняться. Например: 23, part или любое др значение.


app.get('/news/:id', function(req, res){
	res.send('ID is - ' + req.params.id);
});



В зависимости от этого параметра мы можем брать данные из БД (базы данных) и выводить конкретную статью.

Нам нужен некий html файл куда мы будем передавать данные нашего id и в зависимости от этих данных выводить ту или иную информацию.

Нам нужен некий шаблонизатор.

Благодаря Express мы можем использовать несколько шаблонизаторов.

Один из них это EJS

Поскольку EJS является дополнительным пакетом, то нам нужно его установить.

npm install ejs


Нажать Enter

После этого он установится в наш проект.

Он позволяет передавать данные в различные шаблоны, причем эти шаблоны будут иметь расширение .ejs.

В этих шаблонах мы сможем выводить наш html код вместе с вставленным в него js кодом (переменными, выводить циклы и многое другое).

Будет такой шаблон страницы, который будет изменяться в зависимости от переданных в него данных.

Первое, что нам нужно сделать это указать какой view engine мы будем использовать.

view engine - по сути шаблонизатор.

Поскольку их существует огромное количество, а мы выбрали именно EJS, то мы должны его указать в нашем index.js файле.

Сразу после инициализации переменной app.

app.set('view-engine', 'ejs');

Все файлы, которые мы будем отображать, по умолчанию будут искаться в папке views.

На том же уровне, где index.js создадим папку views.

В ней создадим новый файл news.ejs. Это будет некий шаблон, который мы будем наполнять.

В эти шаблоны мы можем помещать самый обычный html-код.

Мы в него добавили обычный html-код:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="wight=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Новости</title>
	<style>
		body {background-color:#98bfd5;}
		.block {text-align: center; width: 70%; margin-left: 15%}
		h1 {color:#494949; font-size: 3.5em}
		p {color:#494949; font-size: 1.2em;}
	</style>
</head>
<body>
	<div class="block">
		<h1>Новостная страница.</h1>
			<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque numquam libero, veniam ipsum similique odit molestiae esse quia blanditiis magni debitis aliquam, pariatur nam quaerat quas nemo, facilis temporibus laboriosam.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores enim vitae dolore nemo quas aliquam quia corrupti rerum ipsam ad nesciunt, architecto, pariatur officiis. Maxime iste ullam quibusdam, nobis voluptas!</p>
	</div>
</body>
</html>



Идем к файлу index.js. Здесь по ссылке /news/:id я хочу выводить наш шаблон.

Для этого мне не нужно использовать метод .send или .sendFile, а мне потребуется метод render().

Метод render() берет нужный файл (шаблон) в папке views и может отобразить его в браузере. Плюс в этот шаблон он может передать некие параметры.

Расширение в методе render() можно не указывать. Далее можно передать некие параметры в сам шаблон. Поэтому мы передаем вторым параметром - объект. В нем может быть большое количество свойств и значений.

Допустим, что мы решили передать некий параметр newsId со значением req.params.id - то есть значение будет как раз сам вызываемый id.


app.get('/news/:id', function(req, res){
	render('news', {newsId: req.params.id});
});



Таким образом в шаблон news будет передано значение, которое будет называться newsId со значением id.

В файл news.ejs мы можем все это принять и отобразить.

Немного изменим наш файл news.ejs. В заголовок страницы будем выводить ID.

Все можно посмотреть в документации к шаблонизатору EJS (ссылка выше).

Ставим <%= и далее имя свойства, значение которого мы хотим увидеть на странице. Закрыть тег - %>

<h1>Новостная страница c ID = <%= newsId %></h1>

Файл /views/news.ejs


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="wight=device-width, initial-scale=1.0">
	<meta http-equiv="X-UA-Compatible" content="ie=edge">
	<title>Новости</title>
	<style>
		body {background-color:#98bfd5;}
		.block {text-align: center; width: 70%; margin-left: 15%}
		h1 {color:#494949; font-size: 3.5em}
		p {color:#494949; font-size: 1.2em;}
	</style>
</head>
<body>
	<div class="block">
		<h1>Новостная страница c ID = <%= newsId %></h1>
			<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque numquam libero, veniam ipsum similique odit molestiae esse quia blanditiis magni debitis aliquam, pariatur nam quaerat quas nemo, facilis temporibus laboriosam.Lorem ipsum dolor sit amet, consectetur adipisicing elit. Maiores enim vitae dolore nemo quas aliquam quia corrupti rerum ipsam ad nesciunt, architecto, pariatur officiis. Maxime iste ullam quibusdam, nobis voluptas!</p>
	</div>
</body>
</html>



Файл index.js


let express = require('express');

let app = express();

app.set('view engine', 'ejs');

app.get('/', function(req, res){
	res.sendFile(__dirname + '/index.html');
});
app.get('/about', function(req, res){
	res.sendFile(__dirname + '/about.html');
});
app.get('/news/:id', function(req, res){
	res.render('news', {newsId: req.params.id});
});
app.listen(8080);





Мы можем передавать несколько параметров. Например:


app.get('/news/:id', function(req, res){
	res.render('news', {newsId: req.params.id, newParam: 535});
});



, а в файле news.ejs выведем его на страницу, например так:

<p><%= newParam %></p>

Помимо этого мы можем передавать и собственные объекты. Например, создадим объект:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4};
	res.render('news', {newsId: req.params.id, newParam: 535});
});



И этот объект мы тоже можем передавать. Вначале определяем название того, что будем передавать, а потом указываем что передаем.

Например:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});




	<p><b>Title = </b><%= obj.title %></p>
	<p><b>ID = </b><%= obj.id %></p>
	<p><%= newParam %></p>





Передача в шаблон массива.

Создадим массив данных и выведем его с помощью цикла.


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



Все, что мы добавили будет передано в шаблон, так как объект obj уже будет передан в шаблон.

Теперь в самом шаблоне мы просто выведем этот массив циклом:


			<ul>
				<% obj.paragraphs.forEach(function(item) { %>
				<li><%= item %></li>
			<% }); %>
			</ul>





Статические файлы и промежуточное ПО.

Файлы, которые можно включить в другие файлы.

Сейчас у нас есть один шаблон - news.ejs, а представьте. что их много. Десятки. И вам потребуется внести изменения в какую-то часть кода, который встречается во всех этих файлах. Придется вносить множество изменений.

Чтобы этого избежать, можно использовать файлы, которые можно включать в другие файлы. Например. Есть файл с шапкой сайта. И если нужно что-то изменить, то достаточно внести изменения только в один файл, так как к другим он просто подключается.

В папке шаблонов views создадим папку blocks , а в ней файл hrader.ejs.

Файл hrader.ejs


<ul>
	<li><a href="/">На главную</a></li>
	<li><a href="/about">Про нас</a></li>
	<li><a href="/news/новости">Новости</a></li>
</ul>



Теперь нам нужно этот файл подключить во всех шаблонах. Идем в файл news и сразу после открывающего тега body записываем:

<% include blocks/header.ejs %>

Путь указывается от папки views, поскольку шаблонизатор всегда начинает искать там.



Статические файлы.

Создадим новую папку на уровне index.js с названием public. В ней будут находиться все статические файлы. Это css-файлы, картинки, документы и пр. Все те файлы. которые будут вызываться с различных страниц нашего сайта.

В этой папке создадим еще одну папку - css и уже в ней создадим файл style.css.

В него перенесем весь код стилей из файла index.ejs

В файлах .ejs подключаем стили:

<link rel="stylesheet" type="text/css" href="/public/css/style.css">

Если теперь проверить, то ничего не произойдет. Стили не подключатся.

Для подключения статических файлов нам нужно использовать промежуточное программное обеспечение:

В файле index.js вверху, сразу за app.set, мы должны написать:

app.use('/public', );

И теперь, если мы где то будем использовать ссылку начинающуюся с /public сам NodeJS и Express будет понимать, что мы используем статические файлы и будет подключать все верно.

вторым - где мы их ищем express.static('public') т. есть в папке /public.

Если обобщить, то в коде app.use('/public', express.static('public')); мы отслеживаем ту ссылку, которую прописываем в

<link rel="stylesheet" type="text/css" href="/public/css/style.css">

Если бы у на было бы вот так:

<link rel="stylesheet" type="text/css" href="/assets/css/style.css">

то и в этом коде было бы:

app.use('/assets', express.static('public'));

В данном случае public указывает на папку!

Если так и оставить, то никаких изменений не произойдет. Файл подключится, потому что мы будем отслеживать ссылку assets .

Перед тем как использовать ссылки на статические файлы, мы должны указать какая папка у нас отвечает за статические файлы (выделил красным) и какая ссылка (желтым) ведет к этим статическим файлам.


app.use('/assets', express.static('public'));



Для того, чтобы не путаться, обычно, делают ссылку и папку одного имени. Чаще всего это именно public.

Промежуточное ПО - это то, что мы делаем до того пока отправим какие-то данные на страницу (сервер).

В данном случае это и есть наше промежуточное ПО.

Создание HTML-формы и получение данных

Первое, что мы сделаем это добавим саму форму на наш сайт.

Открываем файл about.ejs и сюда мы будем добавлять форму используя технологию bootstrap.

Идем на сайт Bootstrap.

Нажимаем на Get Started, копируем css ссылку для подключения и вставляем ее в head файла about.ejs.

В окно поиска вводим Forms и на найденной странице копируем первую форму сверху.

Сохраним и запустим.



POST -запрос.

Так так мы будем выполнять POST -запрос, то нам необходимо добавить в форму несколько атрибутов.

method="post" - т.к POST -запрос

И action="" - это то куда нужно перенаправить пользователя после того,как он нажмет "Отправить". В нашем случае это:

<form method="post" action="/about">

Все остальное нам нужно сделать в файле index.js

Первым делом нам необходимо скачать пакет, который называется body-parser.

Он нам позволяет брать POST -запрос, который идет от формы и обрабатывать его. Проще говоря - получать все данные из формы.

Для установки, в папке проекта в КС пишем.

npm install body-parser


Нажимаем - Enter.

Пакет устанавливается.



После установки стоит следовать простой инструкции.

Перейдем на сайте в раздел Examples и найдем там раздел Express route-specific

  1. Подключаем нужные для нас модули.


  2. var bodyParser = require('body-parser')

    и

    var urlencodedParser = bodyParser.urlencoded({ extended: false })

    То есть тот парсер, который позволит нам брать данные из POST -запроса и работать с ними как нам будет нужно.

  3. Далее, на основе документации, мы видим, что нам нужно отслеживать именно POST -запрос и передавать в него некое промежуточное ПО (urlencodedParser). Ранее мы уже отслеживали GET- запросы.


Данные полученные из формы мы выведем в консоль.

console.log(req.body);

Можно сразу добавить проверку. Если не передано никаких данных из формы, мы выдадим просто ошибку.

if (!req.body) return res.sendStatus(400)

В самой форму нужно указать для полей атрибут name. Это будут названия свойств, а значение - это то, что введет пользователь.

about.ejs


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>О нас.</title>
	<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="/public/css/style.css">

</head>
<body>
	<% include blocks/header.ejs %>
	<div class="container">
		<h1>Hello, It is my first page on Node.js</h1>
		<h2>Заголовок второго уровня.</h2>
		<img src="http://www.chertpz.ru/assets/images/fotogallery_new/phormy_trub/Kvadrat.JPG" alt="">
		<a href="index">На главную</a>
		
		<p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
		<h3>третьего уровня заглавие.</h3>
		<p>Значимость этих проблем настолько очевидна, что консультация с широким активом позволяет выполнять важные задания по разработке систем массового участия. Идейные соображения высшего порядка, а также рамки и место обучения кадров позволяет оценить значение системы обучения кадров, соответствует насущным потребностям. Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
		<p>Не следует, однако забывать, что консультация с широким активом способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям.</p>
		<form method="post" action="/about">
			<div class="form-group">
				<label for="exampleInputEmail1">Email address</label>
				<input type="email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
				<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
			</div>
			<div class="form-group">
				<label for="exampleInputPassword1">Password</label>
				<input type="password" name="pass" class="form-control" id="exampleInputPassword1" placeholder="Password">
			</div>
			<div class="form-check">
				<input type="checkbox" name="check" class="form-check-input" id="exampleCheck1">
				<label class="form-check-label"  for="exampleCheck1">Check me out</label>
			</div>
			<button type="submit" class="btn btn-primary">Отправить</button>
		</form>
	</div>
</body>
</html>



index.js


let express = require('express');
var bodyParser = require('body-parser');
let app = express();

var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.set('view engine', 'ejs');

app.use('/public', express.static('public'));


app.get('/', function(req, res){
	res.render('index');
});


app.get('/about', function(req, res){
	res.render('about');
});

app.post('/about', urlencodedParser, function(req, res){
	if (!req.body) return res.sendStatus(400);
	console.log(req.body);
	res.render('about');
});

app.get('/news', function(req, res) {
	res.render('news-common',{newParam1:'Param-1'});
});
app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});
app.listen(8080);



Введем данные и нажмем отправить. В консоли мы увидим вывод этих данных (свойство - значение).



Страница перезагрузится после отправки формы и в консоли мы увидим данные, которые отправили.

Теперь мы можем сделать так, чтобы после отправки мы показывали другие данные.

Изменим немного код в файле index.js


app.post('/about', urlencodedParser, function(req, res){
	if (!req.body) return res.sendStatus(400);
	console.log(req.body);
	res.render('about-success', {data: req.body});
});



Таким образом мы будем выводить страницу about-success.ejs и мы ее сейчас создадим в папке views. Вторым параметром мы передадим данные формы в виде объекта. - {data: req.body}


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>О нас.</title>
	<link href="https://fonts.googleapis.com/css?family=Poppins" rel="stylesheet">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="/public/css/style.css">

</head>
<body>
	<% include blocks/header.ejs %>
	<div class="container">
		<h1>Hello, It is my first page on Node.js</h1>
		<h2>Заголовок второго уровня.</h2>
		<img src="http://www.chertpz.ru/assets/images/fotogallery_new/phormy_trub/Kvadrat.JPG" alt="">
		<a href="index">На главную</a>
		
		<p>Равным образом укрепление и развитие структуры способствует подготовки и реализации системы обучения кадров, соответствует насущным потребностям. Равным образом начало повседневной работы по формированию позиции требуют от нас анализа существенных финансовых и административных условий.</p>
	  <p>Спасибо</p>
	  <p>
	  	<b>Email:</b> <%= data.email %><br />
	  	<b>Pass:</b> <%= data.pass %><br />
	  	<b>isCheck:</b> <%= data.check %>
	  </p>
	</div>
</body>
</html>





Таким образом вы можете отслеживать данные, которые поступают из форм, проверять их на соответствие и если пользователь что-то не заполнил, то выдавать ошибку и т.д.

Кроме этого было бы удобно отправлять эти данные на почту или сохранять в БД (базу данных).

Если вы хотите отправить их на почту. то в npm есть еще один пакет - Nodemailer. Этот пакет позволяет отправлять данные непосредственно на почту. Использовать его просто. И с помощью него вы можете получать по почте все данные формы, заполненной пользователем.

NodeJS предоставляет нам множество дополнительных пакетов. Например Express мы использовали для того, чтобы проще отслеживать ссылки и использовать шаблонизаторы. Body-parseer для того, чтобы принимать данные полученные из формы. Nodemailer - для отправки данных на почту.

Как получать данные из URL-строки.

Иногда нужно получить такой тип данных из адресной строки :

http://localhost:8080/news/12?filter-id&city=london


Разберем, как получить эти данные на примере вот этого кода из файла index.js:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



Просто выведем эти данные в консоль:


app.get('/news/:id', function(req, res){
	let obj = { title:'Новость', id: 4, paragraphs:['Параграф', 'Обычный текст', 'Числа: 3, 7, 24', 476]};
	console.log(req.query);
	res.render('news', {newsId: req.params.id, newParam: 535, obj: obj});
});



В консоли мы увидим

{ filter: 'id', city: 'london' }




Это может быть иногда полезно.





                                                                                                                                                             


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com