Monacaを使って何かアプリを作ってみたいと思っても、いざとなるとアイディアが出てこないかも知れません。また、最初から大きなアプリを作ろうと思うと、何から手を付けて良いのか分からないことでしょう。

そこで、この記事では手順を踏んで簡単なアプリを開発してみます。最初の一歩として、ぜひチャレンジしてみてください。

今回はNCMB(ニフクラ mobile backend)と組み合わせて、目安箱アプリを開発します。記事は全部で2回に分けており、後半となるこの記事では目安箱への投稿と一覧表示、編集を実装していきます。

※仕様と匿名認証について解説した前半はこちらです。
目安箱アプリを作ってみよう【その1:画面の説明と匿名認証まで】

目安箱への投稿 (form.html)

匿名認証が終わったら、目安箱への投稿を実装していきます。これは投稿ボタン ons.getScriptPage().onInit を押した際のイベントとして実装していきます。

/*
  初期化時に一度だけ実行されるメソッド
*/
ons.getScriptPage().onInit = async function() {
  this.querySelector('#post').onclick = () => postSurvey.bind(this)();
}

/*
  目安箱への投稿を行う
*/
async function postSurvey() {
  // この中に実装します
}

処理の内容です。まず投稿に必要な情報を収集します。

const body = this.querySelector('#body');
const objectId = this.querySelector('#objectId').value;
if (body.value.trim() === '') {
  ons.notification.alert('ご意見を入力してください');
  return;
}

次にニフクラ mobile backendのデータストアに保存する準備をします(別関数 insertPost として定義しています)。詳細はコメントを参照してください。注意点としてACL(アクセス権限)として、データを入力した本人は読み書き可能、adminグループに対して読み込み権限を付与しておきます。こうすることで、adminグループに所属しているユーザはデータ閲覧が可能になります。

async function insertPost(body, objectId) {
  // 投稿用のクラス(Post)を準備
  const Post = ncmb.DataStore('Post');
  // Postクラスのインスタンス(DBでいう行相当)を準備
  const post = new Post();
  // 本文を設定
  post.set('body', body);

  // ACL(アクセス権限)の準備
  const acl = new ncmb.Acl();
  const user = ncmb.User.getCurrentUser();
  acl
    .setUserReadAccess(user, true)
    .setUserWriteAccess(user, true)
    .setRoleReadAccess('admin', true);
  post.set('acl', acl);
  // 保存
  await post.save();
}

後は保存処理を実行します。

try {
  await insertPost(body.value, objectId);
  ons.notification.alert('ご意見ありがとうございました!');
  body.value = '';
} catch (e) {
  ons.notification.alert('エラーが発生しました。もう一度お試しください。');
}

目安箱の投稿表示 (view.html)

次に目安箱への投稿を表示する画面を作成します。これは view.html に実装します。HTMLは次のようになっています。

<ons-navigator id="nav">
  <ons-toolbar>
    <div class="center">意見閲覧</div>
  </ons-toolbar>
  <div style="text-align: center; margin-top: 60px;">
    <ons-list id="posts">
    </ons-list>
  </div>
</ons-navigator>

この画面が表示されたタイミングで、投稿されているデータを取得して表示します。つまり ons.getScriptPage().onShow での処理になります。

/*
  この画面が表示される度に実行されるメソッド
*/
ons.getScriptPage().onShow = async function() {
  // 匿名認証実行
  await loginCheck();
  const posts = await loadPosts();
  showPosts.bind(this)(posts);
}

実際の処理は次のようになります。まずニフクラ mobile backendからデータを取得します。

async function loadPosts() {
  return await ncmb.DataStore('Post')
    .order('createDate')
    .fetchAll();
}

そして取得したデータを ons-list-item で表示します。この時、自分に書き込み権限があるかどうかを判断して、それによって編集画面に遷移できるかどうかを判定しています。

function showPosts(posts) {
  const user = ncmb.User.getCurrentUser();
  this.querySelector('#posts').innerHTML = '';
  // データを順番に表示
  posts.forEach(p => {
    // <ons-list-item>を準備
    const i = document.createElement('ons-list-item');
    // 本文を準備
    let text = p.body;
    // 自分に書き込み権限があるかチェック
    if (p.acl[user.objectId] && p.acl[user.objectId].write) {
      // あれば編集用アイコンの表示
      text = ${p.body} ✏️;
      // 編集イベントの設定
      i.setAttribute('tappable', true);
      i.onclick = () => {
        // form.htmlに遷移
        this.querySelector('#nav').pushPage('form.html', {data: { objectId: p.objectId}});
      }
    }
    // 画面に表示
    i.appendChild(document.createTextNode(text));
    this.querySelector('#posts').appendChild(i);
  });
}

自分が編集できるデータをタップした際には、投稿画面 form.html に遷移します。この時、ニフクラ mobile backendのデータ管理上のユニークIDであるobjectIdを次の画面に送っています。

投稿の編集処理 (form.html)

編集処理を実装する際には、すでに実装されている保存処理をうまく流用して実装していくのがいいでしょう。そうすることで余分な開発が減ります。

まず、一覧画面から送られてきた投稿データを表示する部分を作ります。これは ons.getScriptPage().onShow の中に実装します。

/*
  この画面が表示される度に実行されるメソッド
*/
ons.getScriptPage().onShow = async function() {
  // 匿名認証実行
  await loginCheck();
  if (this.data && this.data.objectId) {
    const post = await fetchPost(this.data.objectId);
    this.querySelector('#body').value = post.body;
    this.querySelector('#objectId').value = post.objectId;
  }
}

async function fetchPost(objectId) {
  return await ncmb.DataStore('Post').equalTo('objectId', objectId).fetch();
}

また、HTMLのhiddenを使ってobjectIdを隠しておきます。
こうすることで新規保存なのか更新なのかを区別します。

  <div style="text-align: center; margin-top: 60px;">
    <ons-row>
      <ons-col>
        <input type="hidden" id="objectId" />
        <textarea id="body" class="textarea" rows="5" cols="40" placeholder="ご意見を入力してください"></textarea>
      </ons-col>
    </ons-row>
    <p style="margin-top: 30px;">
      <ons-button id="post">目安箱に投稿する</ons-button>
    </p>
  </div>

更新処理

新規保存と更新の違いは次の通りです。

  • 新規の場合は save メソッド。更新の場合は update メソッド。
  • 更新の場合は objectId あり。新規の場合はなし。
  • 更新の場合は一覧画面に移動

これらの仕様を反映した保存処理が次の通りになります。

async function insertPost(body, objectId) {
  const Post = ncmb.DataStore('Post');
  const post = new Post();
  if (objectId) {
    post.set('objectId', objectId);
  }
  post.set('body', body);

  const user = ncmb.User.getCurrentUser();
  const acl = new ncmb.Acl();
  acl
    .setUserReadAccess(user, true)
    .setUserWriteAccess(user, true)
    .setRoleReadAccess('admin', true);
  post.set('acl', acl);
  await (objectId ? post.update() : post.save());
}

まとめ

ここまでで目安箱アプリが完成となります。今回は次のような画面を持ったアプリを開発しました。

  • ご意見投稿画面
  • ご意見一覧画面
  • ご意見編集画面

また、ニフクラ mobile backendの次の機能を利用しました。

  • 会員管理
    • 匿名認証
  • データストア
    • Postクラス
    • データ登録
    • データ更新
    • データ検索

今回のデータの保存と取得、更新といった機能はどのようなアプリでも使える機能だと思います。また匿名認証はIDやパスワードの入力が不要な分、ユーザストレスの少ない認証なのでお勧めです。今後のアプリ開発に応用してください。