LoginSignup
1
1

More than 5 years have passed since last update.

meen(mean)でtodoアプリを作成してみた。

Posted at

概要

いまさらながら、気になっていたmean環境をごにょごにょ触って、
mongo + express + ejs + node.js(meen(angularjs不使用))にて、定番のtodoアプリを作ってみました。
なんてことないゴミのようなアプリです。
bower | npm | mongo などの説明は割愛します。

環境

ローカル:
CentOS 6.8
node.js 9.2.0
npm 5.5.1
express 4.15

公開サーバ:
IBM Cloud(bluemix)無料枠

やったこと(メモ)

node.js + npm + bower + mongo は既にローカルで使えるようになっていたので(たぶん気になったときにいれたまま)
expressだけnpmからインストールしました。

webアプリのひな型作成

expressコマンドでひな型を、まず作成します。
デフォルトでviewがjadeになっているようですが、わかりやすそうなejsを指定しました。

express todoapp -e ejs

上記でひな型サイト(アプリ名)のディレクトリができるので、cd todoappをやって、npm startで実行!
するのですが、そのままやるとモジュールないよーエラーになります。

Error: Cannot find module 'express'

npm install or npm i でインストール後、npm startで動きます。
package.jsonに定義してあるscriptsに書いてあるものが動くようです。

ポートはbin/wwwに書いてあって、デフォルト3000になっています。

bowerで使うjsやcssを取得

bower install jquery bootstrap4 underscore

/public/vendor 直下に配置されます。

viewsの修正

views/index.ejsがトップページになっています。app.jsあたりをごにょごにょすれば返れそう。

  <%- include('_head'); %>

などとやれば、ファイルを分けて読み込むことができるのでheader, footer等を外出しにしました。

javascriptをごにょごにょ

javascriptのほうで、jQuery(ajax)を使って登録や読み込みなどを書きました。

main.js
$(function(){
  function getDate(task_date) {
      let date = new Date (task_date);
      let y = date.getFullYear();
      let m = date.getMonth() + 1;
      let d = date.getDate();
      let h = date.getHours();
      let i = date.getMinutes();

      if (m < 10) {
        m = '0' + m;
      }
      if (d < 10) {
        d = '0' + d;
      }
      if (h < 10) {
        h = '0' + h;
      }
      if (i < 10) {
        i = '0' + i;
      }
      return y+'/'+m+'/'+d+' '+h+':'+i;
  }

  function render_task_list(task_list) {
    let tasks = task_list;
    let list_tag = '';
    for(let i = 0; i < tasks.length; i++) {
      list_tag +=
        '<li class="list-group-item" style="padding-left:35px;">'+
          '<label class="form-check-label">'+
          '<input class="form-check-input" type="checkbox" value="" style="margin-top: 20px;margin-left: -25px;">'+
          getDate(tasks[i].create_date)+'<br />'+
          tasks[i].content+
          '</label>'+
          '<button type="button" class="close close_task_list"  data-id="'+tasks[i]._id+'">'+
              '<span>&times;</span>'+
          '</button>'+
        '</li> ';
    }
    $("#task_list").html(list_tag);
  }


  if(!_.isEmpty(localStorage.getItem('task_input_user'))) {
    $('#user_name').val(localStorage.getItem('task_input_user'));
    $('#user_name').prop('disabled', true);

     $.ajax({
      type: 'POST',
      url:'/selecttask',
      dataType: "json",
      data: {user_name:$('#user_name').val()}
    }).done(function(data, textStatus, jqXHR){
      if(data.task_list.length != 0){
        render_task_list(data.task_list);
      } else {
        $("#task_list").html('<li class="list-group-item">'+$('#user_name').val()+'さんのタスクはありません。'+'</li>');
      }
    }).fail(function(jqXHR, textStatus, errorThrown){
    });
  }

  // 閉じるボタン押下時
  $(document).on('click', '.close', function () {
    $(this).parent().slideUp();
  });

  // 取り消し線
  $(document).on('change', '.form-check-input', function () {
    if($(this).prop('checked')){
      $(this).parent().attr('style', 'text-decoration: line-through;');
    } else {
      $(this).parent().attr('style', '');
    }
  });

  // ユーザー名変更 一覧取得
  $("#user_name").change(function(){
    let current_user = $(this).val();
    $.ajax({
      type: 'POST',
      url:'/selecttask',
      dataType: "json",
      data: {user_name:current_user}
    }).done(function(data, textStatus, jqXHR){
      if(data.task_list.length != 0){
        render_task_list(data.task_list);
      } else {
        $("#task_list").html('<li class="list-group-item">'+current_user+'さんのタスクはありません。'+'</li>');
      }
    }).fail(function(jqXHR, textStatus, errorThrown){
    });

  });

  // 一覧削除ボタン押下
  $(document).on('click', '.close_task_list', function () {
    $.ajax({
      type: 'POST',
      url:'/deletetask',
      dataType: "json",
      data: {id:$(this).attr('data-id')}
    }).done(function(data, textStatus, jqXHR){
      $('#info_delete_success').slideDown();
    }).fail(function(jqXHR, textStatus, errorThrown){
      $('#error_delete_faild').slideDown();
    });
  });


  // タスク追加ボタン押下
  $("#btn_add").click(function(){
    // バリデーション
    if(_.isEmpty($('#user_name').val())) {
      $('#alert_empty_user').slideDown();
      return false;
    }

    if(_.isEmpty($('#contents').val())) {
      $('#alert_empty_task').slideDown();
      return false;
    }

    // タスク追加
    $.ajax({
      type: 'POST',
      url:'/addtask',
      dataType: "json",
      data: {user_name:$('#user_name').val(), content:$('#contents').val()}
    }).done(function(data, textStatus, jqXHR){
      $('#info_add_success').slideDown();
      if(data.task_list.length != 0){
        $('#user_name').prop('disabled', true);
        localStorage.setItem('task_input_user', $('#user_name').val());
        render_task_list(data.task_list);
      }
    }).fail(function(jqXHR, textStatus, errorThrown){
      $('#error_add_faild').slideDown();
    });
  });

});

routersの修正

routers/index.jsに取得・登録・削除時にpostでアクセスするので、それぞれ処理を書きました。
mongodbを使うためにmongooseをインストールしました。
後、登録されるデータのXSS対応のためにhtmlspecialcharsモジュールも一緒にいれてみました。

index.js
let mongoose = require('mongoose');
let express = require('express');
let router = express.Router();
let htmlspecialchars = require('htmlspecialchars');

mongoose.connect('mongodb://localhost/todoapp');
const Task = mongoose.model('Task', {user_name: String, content: String, create_date:Date});

/*
* 初期表示
*/
router.get('/', function(req, res, next) {
  res.render('index', {task_list:null});
});

/*
* タスク取得処理
*/
router.post('/selecttask', function(req, res) {
  let post_data = req.body;
  Task.find({user_name:post_data.user_name}, function (err, tasks) {
    if(err) throw err;
    res.send({ task_list:tasks });
  });
});

/*
* タスク追加処理
*/
router.post('/addtask', function(req, res) {
  let post_data = req.body;
  let task = new Task({user_name: htmlspecialchars(post_data.user_name), content: htmlspecialchars(post_data.content), create_date:new Date()});
  task.save(function(err){
    if(err) throw err;

    Task.find({user_name:post_data.user_name}, function (err, tasks) {
      if(err) throw err;
      res.send({message:'ok', task_list:tasks});
    });
  });
});

/*
* タスク削除処理
*/
router.post('/deletetask', function(req, res) {
  let post_data = req.body;
  Task.remove({_id:post_data.id}, function(err){
    if(err) throw err;
  });

  res.send({message:'ok'});
});

module.exports = router;

所感

npmでいろいろインストールして、expressでひな型を作るだけで簡単にページが作れるので楽だと思いますた。
angularjsを現在見ていたりしますが、angular2からangularになって、typescriptになっているので全然作り方が変わるぽいです。
ibm cloudを使ってみましたが、メリットは特に感じませんでした。herokuでもいいかも。

ソース

ソースはこちら。
https://github.com/YasuakiHirano/todoapp
デモ
https://codelike-todoapp-timely-impala.mybluemix.net/
無料枠なので10日後には落ちてるかと思われます。(´・ω...:.;::..

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1