Стоит ли рассказывать, что Ангуляр при всей своей прелести лишь одна сторона медали — frontend, который как то должен взаимодействовать со второй половинкой — backend?
Рассмотрим рабочий пример по стыковке Angular с PHP и передаче данных туда-сюда.
Постановка задачи
Сделаем простейшую форму с текстовым полем, значения из которого будем сохранять в базу по нажатию специальной кнопочки. В ответ сервер нам будет присылать в Angular стандартное сообщение. Что то вроде цитатника великого Мао. :)
Ещё мы будем выводить список уже существующих цитат в базе.
Инструментарий
Понадобится любой LAMP или WAMP веб-вервер, где мы запустим данную тестовую задачу. У меня это WAMP OpenServer.
AngularJS v 1.5.8 мы подключим с серверов google.
Реализация
Проект состоит из 4х файлов + 1 файл скрипта базы данных. Я не стал в этом учебном примере использовать каскадные стили и какое либо оформление вообще, чтобы не загромождать шаблон и не отвлекаться от главного.
Скачать ZIP архив проекта
Два php файла реализуют функционал backend части (папка — api), и два файла — «морду» с помощью фреймворка AngularJS (project.js и index.html).
Начнем с единственного шаблона — index.html.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!doctype html> <html ng-app="projectMao"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <script id="angularScript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script> <script src="/app-js/project.js"></script> </head> <body> <h1>Цитатник Мао</h1> <!-- ПОДКЛЮЧАЕМ КОНТРОЛЛЕР fraseManager --> <div ng-controller="fraseManager as fm"> <label>Добавьте цитату:</label><br /> <input type="text" name="name" ng-model="fm.text" required><br /> <button ng-click="fm.save()">Save</button> <hr /> <ul> <li ng-repeat="txt in fm.history track by $index">{{txt}}</li> </ul> </div> </body> </html> |
Шаблон ссылается на единственный контроллер, используя его свойства .text и .history, а также метод .save() для сохранения новой цитаты.
Каких либо подводных камней на этом этапе не ожидается, так что двинемся дальше.
Реализация контроллера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
angular.module('projectMao', []) // данные будем передавать, используя $http, // это встроенный сервис Ангуляра .controller('fraseManager', function ($http) { var FM = this; // инициализация свойств контролера FM.text = ""; FM.history = []; // передача данных в PHP backend // методом POST-запроса. // в данных - 2 параметра: // command - команда // data - текстовая строка FM.save = function() { if (FM.text !== "") { $http .post('/api/api.php', {'command': 'save', 'data': FM.text}) .success(function (res) { // получаем от сервера текстовое сообщение alert(res['msg']); }); // новую цитату добавляем в массив цитат // angular автоматически обновит отображение // данных, связанных с шаблоном FM.history.push(FM.text); // поле ввода - очистим // для этого достаточно очистить, связанную переменную FM.text = ""; } }; // этот метод также обращается к API, // чтобы прочитать цитаты из базы. // так мы сможем инициализировать список // на сервер передается только код команды // command = loadList FM.loadList = function() { $http .post('/api/api.php', {'command': 'loadList'}) .success(function (res) { FM.history = res; }); } // загрузка списка FM.loadList(); }); |
Проблемы с передачей POST данных из AngularJS в PHP
На этапе передачи данных может возникнуть проблема с получением их на стороне сервера. AngularJS по умолчанию использует в заголовках Content-Type: application/json.
Некоторые фреймворки знают об этой особенности, и транслируют переменные в $_POST массив, в то время как PHP из коробки это не делает. Т.к., во-первых, ожидается Content-Type вроде такого:
1 |
application/x-www-form-urlencoded; charset=utf-8 |
и, во-вторых, переменные, как указывает тип содержимого, должны быть сформированы в строку, с использованием url-encode алгоритма.
Решений здесь много.
Можно даже заставить Angular передавать данные как надо, но я предпочитаю решать проблему со стороны сервера.
Итак, посмотрим как реализовано api на PHP.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<?php /* пара заголовков борются с кешированием в данной задаче это не слишком актуально */ header("Cache-Control: no-cache, must-revalidate"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); /* покажем тип содержимого и ответ сервера, вообще то мы будем отправлять совсем не text/html в ответ, но Angular это переживет. :) */ header('Content-Type: text/html; charset=UTF-8'); header("HTTP/1.1 200 OK"); /* рутину, связанную с работой с базой, я спрятал в отдельный файл */ require_once dirname(__FILE__) . '/db.php'; /* грузим данные, которые AngularJS шлет мимо $_POST функция будет в самом низу :) */ $vars = get_angular_request_payload(); /* тут формируем результат - ответ сервера*/ $result = array(); /* реализация API, обработка команд серверу */ switch ($vars['command']) { case 'loadList': $res = db_query("SELECT * FROM mao_text"); if ($res->num_rows) while ($r = $res->fetch_object()) $result[] = $r->txt; break; case 'save': db_query("INSERT INTO mao_text (txt) VALUES (:txt)", array(':txt' => $vars['data'])); $result['msg'] = "Данные сохранены!"; break; } /* отправляем данные в виде json */ echo json_encode($result, true); /* ТА-ДАМ! а вот способ, того как решается проблема с получением данных это избавляет нас менять заголовки и форматировать данные на стороне front-end, в Angular */ function get_angular_request_payload() { return json_decode(file_get_contents('php://input'), true); } |
Данные удалось извлечь из стандартного потока php://input. Они также могут содержаться в $HTTP_RAW_POST_DATA (зависит от настроек в php.ini). Но первоисточник советует получать raw данные именно из потока (смотрите пункт php://input).
Остались за кадром вспомогательный файл подключения работы с БД и скрипт SQL, но они есть в архиве.
СПАСИБО ! Очень помогло !
как скачать все файлы?
Ссылка почти в начале статьи (Скачать ZIP архив проекта)
https://shra.ru/wp-content/uploads/2016/11/angularJS-mao-sample.zip