💻
Documentação para desenvolvedores
  • Formação para desenvolvedores
    • Introdução
    • Entidades
    • Controladores
    • Backend dos Temas
    • Frontend dos Temas
    • Plugins
    • Módulo AngularJS
  • 📖Livro de receitas
    • Criação de um Tema
    • Adicionando campos adicionais ao seu tema
    • Gerando certificados personalizados para os selos
  • APIs
    • Guia de Hooks
Powered by GitBook
On this page
  • Esqueleto do Módulo
  • Enfileirando Arquivo JS
  • Chamando o Módulo no Template
  • Listando Itens
  • Recuperando Itens do Banco de Dados
  • Inserindo Itens
  • Deletando Itens
  • Modificando Itens
  • Adicionando Campo de Busca
  • Incluindo Módulo em Outras Páginas

Was this helpful?

  1. Formação para desenvolvedores

Módulo AngularJS

Esse capítulo aborda a criação de um módulo AngularJS completo, contendo controlador, serviço CRUD e interface para listagem, criação, modificação e deleção de objetos de uma entidade.

PreviousPluginsNextCriação de um Tema

Last updated 3 years ago

Was this helpful?

A implementação abordada é continuação do plugin criado no capítulo anterior. O CRUD será em cima da entidade Item.

Antes da abordagem da implementação do módulo em si, vamos criar uma base para testes. Uma rota /meu-plugin/itens, um arquivo de visão e um template part com o template angular da listagem.

// arquivo Controllers/MeuPlugin.php
    function GET_itens () {
        $this->requireAuthentication();
        $this->render('items');
    }
// arquivo views/meu-plugin/items.php
<div class="main-content">
    <?php $this->part('meu-plugin/items-list'); ?>
</div>
// layouts/parts/meu-plugin/items-list.php
<div>
  <h1>Lista de itens</h1>
  <ul>
    <li>Item 1 - <a>remover</a></li>
    <li>Item 2 - <a>remover</a></li>
  </ul>
</div>

Esqueleto do Módulo

Primeiro, deve-se criar um arquivo JS com o esqueleto do módulo contendo controller e service vazios. É necessário modificar o conteúdo das requisições para que o Angular não envie um JSON no corpo da requisição, pois o Slim não vai parsear corretamente.

// arquivo assets/js/meu-plugin/ng.module.item.js
(function (angular) {
    var module = angular.module('module.item', ['ngSanitize']);

    // modifica as requisições POST para que sejam lidas corretamente pelo Slim
    module.config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
        $httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
        $httpProvider.defaults.headers.common['X_REQUESTED_WITH'] = 'XMLHttpRequest';
        $httpProvider.defaults.transformRequest = function (data) {
            var result = angular.isObject(data) && String(data) !== '[object File]' ? $.param(data) : data;

            return result;
        };
    }]);

    // Seriço que executa no servidor as requisições HTTP
    module.factory('ItemService', ['$http', function ($http) {
        return {};
    }]);

    // Controlador da interface
    module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
        $scope.data = {};
    }]);
})(angular);

Enfileirando Arquivo JS

Com o arquivo JS do módulo criado, é necessário que ele seja incluído na visão. Isto pode ser feito de diferentes maneiras, mas para este exemplo, faremos o enfileiramento no próprio arquivo do template part:

// layouts/parts/meu-plugin/items-list.php
<?php 
$this->enqueueScript(
    'app', // grupo de scripts
    'ng-module-item',  // nome do script
    'js/meu-plugin/ng.module.item.js', // arquivo do script
    [] // dependências do script
);
?>
<div>
  <h1>Lista de itens</h1>
  <ul>
    <li>Item 1 - <a>remover</a></li>
    <li>Item 2 - <a>remover</a></li>
  </ul>
</div>

Chamando o Módulo no Template

O AngulaJS precisa de um elemento com a diretiva ng-app que indica qual o módulo principal da página. Como utilizaremos o módulo numa nova rota que ainda não tem nenhum ng-app definido, colocaremos a propriedade na tag com a classe main-content:

// arquivo views/meu-plugin/items.php
<div ng-app="module.item" class="main-content">
    <h1> Lista de itens </h1>
    <?php $this->part('meu-plugin/items-list'); ?>
</div>

Definido o ng-app, podemos chamar o controlador no arquivo do template part colocando a diretiva ng-controller na div que envolve o ul:

// arquivo layouts/parts/meu-plugin/items-list.php
<div ng-controlle="ItemController">
  <h1>Lista de itens</h1>
  <ul>
    <li>Item 1 - <a>remover</a></li>
    <li>Item 2 - <a>remover</a></li>
  </ul>
</div>

Listando Itens

Vamos primeiro colocar no controller alguns itens fakes no objeto $scope.data para utilizarmos na listagem:

// Controlador da interface
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
  $scope.data = {
    items: [
      {id: 1, title: 'Título 1'},
      {id: 2, title: 'Título 2'}
    ]
  };
}]);

Em seguida, fazemos a iteração no template utilizando a diretiva ng-repeat na tag li:

// layouts/parts/meu-plugin/items-list.php
<div ng-controller="ItemController">
  <h1>Lista de itens</h1>
  <ul>
    <li ng-repeat="item in data.items">{{item.title}} - <a>remover</a></li>
  </ul>
</div>

Para testar a listagem é necessário, nesse ponto, inserir algumas entradas na tabela item.

Recuperando Itens do Banco de Dados

Vamos implementar uma função no serviço que consulta a API de busca da entidade item:

// arquivo assets/js/meu-plugin/ng.module.item.js

// Seriço que executa no servidor as requisições HTTP
module.factory('ItemService', ['$http', function ($http) {
  return {
    find: function(keyword) {
      var endpoint = MapasCulturais.baseURL + 'api/item/find';
      var params = {'@select': '*'};

      // para possibilitar filtro 
      if (keyword) {
        params.title = 'ILIKE(*' + keyword + '*)';
      }
      return $http.get(endpoint, {params});
    }
  };
}]);

Em seguida, removemos os itens fakes do array de itens, implementamos função no controlador que chama a função find do serviço e chamamos essa função no controller para trazer os itens da API:

// arquivo assets/js/meu-plugin/ng.module.item.js

// Controlador da interface
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
  $scope.data = {
    items: []
  };

  // busca itens na api
  $scope.findItems = function (keyword) {
    ItemService.find(keyword).then(function(result) {
      $scope.data.items = result.data;
    });
  }

  // faz a busca assim que carrega a página
  $scope.findItems();

Inserindo Itens

No serviço, criamos uma função insert que faz uma requisição POST em /item:

// arquivo assets/js/meu-plugin/ng.module.item.js

// Serviço que executa no servidor as requisições HTTP
module.factory('ItemService', ['$http', function ($http) {
  .
  .
  .
  // faz uma requisição do tipo POST
  insert: function(item) {
    var endpoint = MapasCulturais.createUrl('item', 'index');
    return $http.post(endpoint, item);
  },

No controlador, adicionamos uma propriedade para guardar o título do novo item, criamos uma função que utiliza essa variável para criar um item e enviar para o serviço:

// arquivo assets/js/meu-plugin/ng.module.item.js

// Controlador da interface
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
  $scope.data = {
    newItemTitle: '',
    items: []
  };

  $scope.insertItem = function () {
  if($scope.data.newItemTitle) {
    var item = { title: $scope.data.newItemTitle };
    ItemService.insert(item).then(function (result) {
      $scope.data.items.push(result.data);
      $scope.data.newItemTitle = '';
    });
  }
}

Antes da listagem, adicionamos um formulário para criação de novo item:

// layouts/parts/meu-plugin/items-list.php
<div ng-controller="ItemController">
  <h1>Lista de itens</h1>
  <form>
    <input type="text" placeholder="Título do novo item" ng-model="data.newItemTitle">
    <button ng-click="insertItem()">criar novo item</button>
  </form>

Deletando Itens

No serviço, criamos uma função remove que faz uma requisição http do tipo DELETE para /item/single/{id}.

// arquivo assets/js/meu-plugin/ng.module.item.js

// Serviço que executa no servidor as requisições HTTP
module.factory('ItemService', ['$http', function ($http) {
  return {
    .
    .
    .
    // faz uma requisição DELETE para deletar um item
    remove: function (item) {
      var endpoint = MapasCulturais.createUrl('item', 'single', [item.id]);
      return $http.delete(endpoint);
    }

No controlador, criamos uma função $scope.removeItem que chama a função remove do serviço:

// arquivo assets/js/meu-plugin/ng.module.item.js
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
    .
    .
    .

    // deleta um item
    $scope.removeItem = function(item) {
      ItemService.remove(item).then(function () {
        var index = $scope.data.items.indexOf(item);
        if (index > -1) {
          $scope.data.items.splice(index, 1);
        }
      });
    }

E, chamamos ela no click do link remover:

// layouts/parts/meu-plugin/items-list.php
<div ng-controller="ItemController">
  <h1>Lista de itens</h1>
  <ul>
    <li ng-repeat="item in data.items">{{item.title}} - <a ng-click="removeItem(item)">remover</a></li>
  </ul>
</div>

Modificando Itens

No serviço, criamos uma função update que faz uma requisição http do tipo PUT para /item/single/{id}:

// arquivo assets/js/meu-plugin/ng.module.item.js
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
    .
    .
    .

    // atualiza um item
    update: function(item) {
      var endpoint = MapasCulturais.createUrl('item', 'single', [item.id]);
      return $http.put(endpoint, item);
    },

No controlador, adicionamos uma nova chave no $scope.data para guardar uma cópia do item que será editado.

E, adicionamos duas funções no $scope, a primeira que faz a cópia do objeto e a segunda que salva o objeto copiado.

// arquivo assets/js/meu-plugin/ng.module.item.js   
module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
  $scope.data = {
    newItemTitle: '',
    editItem: null,
    items: []
  };

  // copia o item para edição
  $scope.editItem = function (item) {
    $scope.data.editItem = angular.copy(item);
  }

  // modifica um item
  $scope.updateItem = function(item) {
    ItemService.update($scope.data.editItem).then(function (result) {
      var index = $scope.data.items.indexOf(item);
      if (index > -1) {
        $scope.data.items[index] = result.data;
        $scope.data.editItem = null;
      }
    });
  }

No template, modificamos o conteúdo da tag li adicionando um formulário e um link para edição que chama a função $scope.editItem. Esta, faz uma cópia do item para o $data.editItem fazendo com que a condição para exibição do formulário seja verdadeira e que assim, o formulário é exibido:

// layouts/parts/meu-plugin/items-list.php
    <li ng-repeat="item in data.items">
      <p ng-if="data.editItem.id != item.id"> 
        {{item.title}} 
        - <a ng-click="editItem(item)">editar</a> 
        - <a ng-click="removeItem(item)">remover</a>
      </p>
      <form ng-if="data.editItem.id == item.id">
        <input type="text" ng-model="data.editItem.title" />
        <button ng-click="updateItem(item)">salvar</button> 
        <button ng-click="data.editItem=null">cancelar</button>
      </form>
    </li>

Adicionando Campo de Busca

Como já havíamos possibilitado as buscas no método find do serviço, só precisamos modificar o controlador e o template.

No controlador adicionamos uma nova chave no objeto $scope.data para guardar o termo buscado, além de uma função que efetua a busca:

// arquivo assets/js/meu-plugin/ng.module.item.js
    // Controlador da interface
    module.controller('ItemController', ['$scope', 'ItemService', function ($scope, ItemService) {
        $scope.data = {
            newItemTitle: '',
            editItem: null,
            items: [],
            search: ''
        };

        $scope.searchItems = function () {
            $scope.findItems($scope.data.search);
        }

No template colocamos um formulário para a busca:

// layouts/parts/meu-plugin/items-list.php
  <form>
    <input type="text" ng-model="data.search"/>
    <button ng-click="searchItems()">buscar</button>
  </form>

Incluindo Módulo em Outras Páginas

@todo