Создание движка для форума с помощью Meteor и AngularJS

Меня часто просят создать небольшие HTML форумы для пользователей веб-сайта и службы поддержки. Так что я решил рассказать о том, как это сделать при помощи Meteor и AngularJS:

Создание движка для форума при помощи Meteor и AngularJS Для начала установим Meteor! Откройте командную строку и вставьте следующую команду:

$ curl https://install.meteor.com/ | sh

Если же вы используете Windows, загрузите официальную программу установки Meteor.

Сейчас создадим новое приложение Meteor.

$ meteor create forum

Откройте каталог forum и удалите автоматом сгенерированные файлы: forum.css, forum.html и forum.js.

$ cd forum$ rm forum.css forum.html forum.js

Я хочу установить Angular-Meteor, удалив ненужные пакеты — blaze-html-templates, ecmascript, autopublish и insecure. Начиная с Meteor v1.2, необходимо вручную добавить check, чтобы выполнить базовую санитизацию ввода:

$ meteor remove blaze-html-templates ecmascript autopublish insecure$ meteor add angular check

Создадим каталоги client и views в корне проекта. Первый представляет собой специальный каталог Meteor, который включает код, используемый только на стороне покупателя. Хотя Meteor может написать код, выполняемый как на стороне покупателя, так и на стороне сервера. Это довольно хорошая идея отделить бизнес-логику по соображениям безопасности. Давайте поместим HTML-шаблоны для верстки страниц и каталогов AngularJS в папку views:

$ mkdir client$ mkdir views

Продолжим реализацию форума для веб-сайта HTML. Создайте файл index.html в корневом каталоге проекта и разместите приведенный ниже программный код внутри него:

<head> <title>Angular-Meteor Forum</title></head><body ng-app="forum"> <div ng-include="'views/forum.html'"></div></body>

Это будет загрузочный модуль forum AngularJS, который ещё не существует. Он содержит шаблон views/forum.htm, который также ещё не существует. Давайте исправим это.

Для начала исправим модуль AngularJS. Создайте файл client/app.js и определите модуль:

angular.module('forum', ['angular-meteor']);

Далее создайте шаблон форума views/forum.html. Это будет общий макет, используемый всеми страницами:

<div class="forum"> FORUM</div>

На этом этапе можно без проблем запустить приложение.

$ meteor

Откройте браузер и перейдите по адресу http://localhost:3000. Вы должны увидеть текст FORUM. Давайте создадим шаблон views/pages/topics.html для выведения тем HTML форума:

<div class="page"> <h1>Topics</h1> <div ng-repeat="topic in topics"> <a ui-sref="topic({topicId: topic._id})">{{ topic.name }}</a> </div></div>

Чтобы увидеть этот шаблон в действии, мы установим решение для маршрутизации в AngularJSangular-ui-router, и определим основные маршруты. Выйдите из Meteor при помощи Ctrl+C или вновь откройте командную строку и перейдите к корневой папке приложения:

meteor add angularui:angular-ui-router

Созданный нами app.js — отличное место для параметра маршрутизации и контроллеров. Тем не менее, вы можете без труда поместить их в различные файлы. Если сделаете это, то убедитесь, что Meteor загружает файлы. Поместите определение модуля в файл client/lib/, иначе он будет загружен после контроллера и каталога, вызывая исключение в AngularJS.

Замените содержимое файла app.js:

angular.module('forum', ['angular-meteor', 'ui.router']).config(function($urlRouterProvider, $stateProvider){ // Установка маршрута по умолчанию    $urlRouterProvider     .when('/', '/topics')        .otherwise('/topics');    // Добавление состояния    $stateProvider.state('topics', {        url: '/topics',        templateUrl: 'views/pages/topics.html'    });}).run(function($state){    // Мы вводим $state здесь, чтобы инициализировать ui.router })

Прежде чем список тем отобразится в браузере, необходимо доработать файл views/forum.html . Нам необходим элемент с атрибутом ui-view для отрисовки шаблона форума HTML , связанного с текущим маршрутом:

<div class="forum">    <div class="page-container" ui-view>    </div></div>

Перейдите теперь по адресу http://localhost:3000 и обратите внимание, что вы мгновенно перенаправляетесь на страницу тем. Но у нас ещё нет тем. Так как мы захотим добавить или удалить темы, будет хорошей идеей сохранить их в базе данных.

Meteor использует СУБД MongoDB . Можно определить коллекции MongoDB при помощи new Meteor.Collection (collectionName). Этот программный код должен присутствовать и на стороне покупателя, и на стороне сервера, так что создадим каталог common и поместим данную строку в common/db.js :

Topics = new Meteor.Collection('Topics');

В Meteor публикация — это метод построения набора данных для отправки покупателю. Вы вызываете Meteor.publish с именем набора данных, и функцию обратного вызова возвращает курсор в mongodb . Meteor считывает изменения из mongodb oplog (или опрашивает базу данных, если oplog не установлен должным образом) и обновляет курсор, когда данные добавлены, удалены или изменены.

Публикация должна быть определена в файле только для сервера, так что создадим папку server . Каждый JavaScript-файл , который вы помещаете сюда, будет работать только на сервере.

Создадим файл server/publications.js :

Meteor.publish('topics', function(){    return Topics.find();});Meteor.publish('topic', function(id){    check(id, String);    return Topics.find({_id: id});});

Это сможет определить две публикации в форуме для веб-сайта HTML : одну для всех тем и одну для той, которую запрашивает идентификатор. Кроме этого, давайте вставим некоторые темы по умолчанию, если коллекция пуста. Поместите приведенный ниже код в server/defaults.js :

if (Topics.find().count() === 0) {    _.each(['General Discussion', 'Tutorials', 'Help'], function(topicName){        Topics.insert({name: topicName});    });}

Покупатель инициирует подписку, которая подключается к публикации, и получает данные данные. Давайте посмотрим, как это сделать при помощи Angular-Meteor . В client/app.js добавьте настройка контроллера в определение состояния topics , называемого TopicsContoller , и определите контроллер после .run() :

// ...        $stateProvider.state('topics', {            url: '/topics',            templateUrl: 'views/pages/topics.html',            controller: 'TopicsContoller'        });// ....controller('TopicsContoller', function($scope){    $scope.subscribe('topics');    $scope.helpers({        topics: function() {            return Topics.find({}, {sort: {name:1}});        }    });})

Здесь мы присоединились к публикации topics , а также добавили помощника с именем topics , который возвращает курсор MongoDB на список тем, отсортированных по именам. С точки зрения AngularJS это простой массив, доступный в переменной $scope.topics .

Посмотрите HTML форум в браузере. Вы должны увидеть три темы в соответствии с заголовком. Тем не менее, если кликнуть по ним, ничего не произойдет. Это потому, что мы не определили состояние topic . Давайте сделаем это и определим TopicController :

// ...        $stateProvider.state('topic', {            url: '/topic/:topicId',            templateUrl: 'views/pages/topic.html',            controller: 'TopicContoller'        });// ....controller('TopicContoller', function($scope, $stateParams){    $scope.subscribe('topic', function(){ return [$stateParams.topicId]; });    $scope.helpers({        topic: function() {            return Topics.findOne({_id: $stateParams.topicId});        }    });})

Это довольно просто, но учтите, что необходимо использовать возможность, чтобы передать аргумент идентификатора topics публикации и вернуть одну тему с findOne вместо find .

Шаблон views/pages/topic.html будет довольно простым, но не волнуйтесь, мы скоро добавим список ветвей обсуждения:

<div class="page">    <h1>{{ topic.name }}</h1></div>

Чтобы использовать HTML код форума для веб-сайта, необходимо идентифицировать посетителей. У Meteor есть полезные пакеты для аутентификации:

  • accounts-base : Этот пакет реализует основные возможности, необходимые для учетных записей посетителей и может иным пакетам использовать службы входа в систему;
  • accounts-password : служба, которая имеет безопасный, основанный на пароле, вход в систему;
  • dotansimha:accounts-ui-angular : AngularJS «контейнер» для пакета UI учетной записи Meteor.

Давайте установим их:

$ meteor add accounts-base accounts-password dotansimha:accounts-ui-angular

Для использования dotansimha:accounts-ui-angular модуль AngularJS должен указать accounts.ui в виде зависимости:

angular.module('forum', ['angular-meteor', 'ui.router', 'accounts.ui'])

Сейчас можно добавить аутентификацию, регистрацию, возможности: forgot password и change password при помощи одной строки. Лучше всего прописать все это в views/forum.html , так как это корневое расположение для всех страниц шаблона форума HTML :

<div class="forum">    <login-buttons></login-buttons>    <div ui-view>    </div></div>

Пора создать потоки выполнения:

  • Определить коллекцию common/db.js :
Threads = new Meteor.Collection('Threads');
  • Опубликовать треды (ветви обсуждения) в server/publications.js :
Meteor.publish('threads', function(topicId){    check(topicId, String);    return Threads.find({topicId: topicId});});Meteor.publish('thread', function(id){    check(id, String);    return Threads.find({_id: id});});
  • Отредактировать views/pages/topic.html , чтобы перечислить треды темы и добавить форму, где посетители могут создавать новые ветви обсуждения:
<div class="page">    <h1>{{ topic.name }}</h1>    <ul>        <li ng-repeat="thread in threads">            <a ui-sref="thread({threadId: thread._id})">{{ thread.content }}</a>            by {{ thread.author }} at {{ thread.createdAt | date }}        </li>    </ul>    <h2>Create a new thread</h2>    <form ng-submit="createThread(thread)">        <input type="text" placeholder="Start discussion..." ng-model="thread.content">        <button type="submit">Create</button>    </form></div>
  • Настроить TopicController в client/app.js так, чтобы он подписался к списку тредов, которые принадлежат текущей теме, и управлял созданием ветвей обсуждения:
.controller('TopicContoller', function($scope, $stateParams, $meteor){    $scope.subscribe('topic', function(){ return [$stateParams.topicId]; });    $scope.subscribe('threads', function(){ return [$stateParams.topicId]; });    $scope.helpers({        topic: function() {            return Topics.findOne({_id: $stateParams.topicId});        },        threads: function() {            return Threads.find({topicId: $stateParams.topicId});        }    });    $scope.createThread = function(thread){        $meteor.call("createThread", $stateParams.topicId, thread.content).then(function(){            thread.content = '';        }).catch(function(){            alert("An error occured while creating the thread!");        });    };})

Увидели вложенную службу $meteor ? Мы используем ее для вызова серверного способа createThread , который ещё предстоит создать.

Вставьте приведенный ниже программный код в файл HTML форума server/methods.js :

Meteor.methods({    createThread: function(topicId, content){        check(topicId, String);        check(content, String);        var user = Meteor.user();        if (!user) {            throw new Meteor.Error("You are not logged in!");        }        if (!content){            throw new Meteor.Error("Content is required!");        }        var thread = {            author: user.emails[0].address,            createdAt: new Date(),            topicId: topicId,            content: content        };        return Threads.insert(thread);    }       });

Meteor.methods ожидает объект, в котором ключи — имена способов, а значения — определения способов. Способы могут иметь аргументы и могут возвратить что-либо, что может быть сериализовано в формате JSON . Курсоры Meteor не сериализуются, так что постарайтесь избежать возвращения collection.find(…) , так как это приведет к краху приложения.

Давайте подведем итоги. Мы можем:

  • Перечислить темы;
  • Открыть темы со списком тредов;
  • Создать треды;
  • Зарегистрироваться / войти / выйти, сбросить забытый пароль и настроить пароль.

Что осталось сделать:

  • Определить коллекцию Posts и опубликовать ее так же, как это сделали с Threads ;
  • Создать маршрут для одной темы, чтобы перечислить сообщения так же, как это сделали с topic ;
  • Создать форму, чтобы публиковать тему, как это сделали с topic ;
  • Написать способ для создания записи, как мы это сделали с createThread .

Вы готовы к реализации проекта? Не волнуйтесь, вы можете без труда посмотреть пример создания форума на веб-сайте HTML в репозитории GitHub .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *