Paso 3: Ver las reviews de un libro - Relación composite

URL: https://github.com/Uniandes-isis2603/frontstepbystep.git
Release: git checkout -f paso-3

Aplicación

Requerimientos nuevos

  1. Al mostrar el detalle de un libro se tiene se despliegan sus reviews

Cambios importantes

  1. Actualizar el template del detalle de book para que se pueda acceder a los reviews.
  2. Crear el nuevo módulo reviewModule en el archivo reviews/reviews.mod.js
  3. Crear el controlador
  4. Actualizar el index.html y app.js para incluir el nuevo módulo

Actualizar el template del detalle de book

El template del detalle de book tiene dos nuevos elementos:

  • uno para que el usuario obtenga los reviews (en el ejemplo lo hicimos con un nav-tabs . Este elemento tiene el enlace al estado de listar los reviews reviewsList. Note que este estado recibe de parámetro el id del book actual.
ui-sref="reviewsList({bookId: currentBook.id})"
  • un nuevo divque define una nueva vista, la hemos llamado childrenView que se utilizará en el módulo de reviewModule para desplegar la lista de reviews.
<div ui-view="childrenView"></div>

La parte final del archivo books.detail.html es entonces:

<div class="panel panel-default"> ... ... ... <ul class="nav nav-tabs"> <li class="active"> <a ui-sref="reviewsList({bookId: currentBook.id})">Reviews</a></li> </ul> </div> </div> </div> </div> <div class="row"> <div class="col-md-3"></div> <div class="col-md-9"> <div ui-view="childrenView"></div> </div> </div>

Crear modulo para review

El módulo review tiene, por ahora, dos estados:

  • reviews: estado abstracto que hereda de bookDetail para así tener acceso al id del libro que está seleccionado.
  • reviewsList: estado para listar los reviews; este hereda del estado anterior reviews

La siguiente figura muestra la jerarquía de estados entre book y review:

Estado reviews

El estado reviews es un estado abstracto. Este estado utiliza la vista childrenView que fue definida en el estado padre bookDetail.

var mod = ng.module("reviewModule", ['bookModule', 'ui.router']); mod.constant("reviewsContext", "reviews"); mod.constant("booksContext", "api/books"); mod.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) { var basePath = 'src/modules/reviews/'; $urlRouterProvider.otherwise("/reviewsList"); $stateProvider.state('reviews', { url: '/reviews', abstract: true, parent: 'bookDetail', views: { childrenView: { templateUrl: basePath + 'reviews.html' } } }).state('reviewsList', { ... }); }]);

Template reviews.html

El template reviews.html se despliega en la zona llamada childrenView. Este template a su vez define dos zonas: una para el detalle del review y otra para la lista de reviews.

<div class="container-fluid"> <div class="row"> <div ui-view="detailView"></div> </div> <div class="row"> <div ui-view="listView"></div> </div> </div>

Estado reviewsList

El estado reviewsList tiene com padre el estado abstracto reviews. Su template es reviews.list.html y su controlador es reviewsCtrl

$stateProvider.state('reviews', {...}) .state('reviewsList', { url: '/list', parent: 'reviews', views: { 'listView': { templateUrl: basePath + 'reviews.list.html', controller: 'reviewsCtrl', controllerAs: 'ctrl' } } });

Crear el controlador para los reviews

En el controlador, hacemos uso del $state para obtener el id del libro que se esta consultando, y se hace una petición de tipo GET que nos trae los reviews asociados con el libro. Es decir,

a través de la ruta "/api/books/idBook/reviews"

var mod = ng.module("reviewModule"); mod.constant("reviewsContext", "reviews"); mod.constant("booksContext", "api/books"); mod.controller('reviewsCtrl', ['$scope', '$http', 'booksContext', '$state', 'reviewsContext', function ($scope, $http, booksContext, $state, reviewsContext) { $http.get(booksContext + '/' + $state.params.bookId + '/' + reviewsContext).then(function (response) { $scope.reviewsRecords = response.data; }); } ]);

Actualizaciones para incluir el nuevo modulo

Siempre que se define un nuevo módulo se deben agregar todos los archivos javascript del módulo en el index y se debe definir en el módulo principal la dependencia al nuevo.

index.html

El nuevo módulo reviews tiene el archivo donde se redefine el módulo y el archivo donde se define el controlador del módulo.

<!-- Reviews--> <script src="src/modules/reviews/reviews.mod.js" type="text/javascript"></script> <script src="src/modules/reviews/reviews.ctrl.js" type="text/javascript"></script>

app.js

En el módulo mainApp se incluye la nueva dependencia a reviewModule.

(function (ng) { var app = angular.module('mainApp', [ // External dependencies 'ui.router', // Internal modules dependencies 'bookModule', 'authorModule', 'editorialModule', 'reviewModule' ]);

Mejoras pantalla inicial

En este paso también se harán algunas mejoras a la pantalla inicial.

  1. Ver un encabezado
  2. Ver un footer

Cambios importantes

  1. Crear el nuevo encabezado en el index.html
  2. Crear el nuevo footer en el index.html

Nuevo encabezado

Para realizar este encabezado tenemos dentro de la división del container-fluid dos filas (row):

  • una para mostrar el título, la imagen y los botones de Sign Up y login
  • otra para mostrar la barra de menús y el icono del shopping cart

Los distintos glyphicon de bootstrap, como los utilizados para login, signout o shopping cart, pueden ser encontrados aquí.

<body class="span4"> <div class="container-fluid"> <div class="row mainHeader"> <div class="col-md-1"> <img src="resources/images/img_tree.png" alt="logo" class="img-responsive logo"/> </div> <div class="col-md-6"> <h2 class="mainTitle">B O O K S T O R E</h2> </div> <div class="col-md-5"> <ul class="nav navbar-nav navbar-right"> <li><a href="#"><span class="glyphicon glyphicon-user"></span> Sign Up</a></li> <li><a href="#"><span class="glyphicon glyphicon-log-in"></span> Login</a></li> </ul> </div> </div> <div class="row"> <div class="col-md-12"> <ul class="nav nav-tabs"> <li role="navigation"><a ui-sref="booksList">Books</a></li> <li role="presentation"><a ui-sref="authorsList">Authors</a></li> <li role="presentation"><a ui-sref="editorialsList">Editorials</a></li> <ul class="nav navbar-right"> <div class="shoppingCart-custom "> <button type="button" class="btn btn-default btn-sm"> <a href="#"><span class="glyphicon glyphicon-shopping-cart"></span> Shopping Cart Checkout</a> </button> </div> </ul> </ul> </div> </div> <div class="span4" ui-view="mainView"></div> </div> <br> <br> <div class="navbar navbar-default navbar-fixed-bottom"> <div class="container"> <p class="navbar-text pull-left">© Ejemplo Desarrollo de Sw en Equipos <a ui-sref="booksList">Bookstore</a> <img src="resources/images/Logo_Uniandes.png" alt="logo" width="8%" /></a> </p> </div> </div> </body>

Estilos

Los estilos mainHeader, mainTitleestán definidos en el archivo resources/css/app.css

.margin-top{ padding-top: 20px; } .mainHeader { padding: 20px; } .logo{ display: block; object-fit: cover; } .mainTitle { font-variant: small-caps; font-style: italic; } .footerTitle { font-variant: small-caps; font-weight: bold; } .shoppingCart-custom{ padding-right: 13px; }

El footer, de este ejemplo, es una franja en la parte baja de la pantalla que aparecerá siempre en la aplicación. En el index.html tenemos al final del body la definición del footer así:

<div class="navbar navbar-default navbar-fixed-bottom"> <div class="container"> <p class="navbar-text pull-left">© Ejemplo Desarrollo de Sw en Equipos <a ui-sref="booksList">Bookstore</a> <img src="resources/images/Logo_Uniandes.png" alt="logo" width="8%" /></a> </p> </div> </div>

results matching ""

    No results matching ""