├── .gitignore ├── README.md ├── app.js ├── cervejarias.json ├── index.html └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Vedcasts.com.br - Séries - Vue.js 2 | 3 | O código fonte deste repositório foi desenvolvido durante a série de aulas sobre Vue.js encontrada em [http://www.vedcasts.com.br/series/vuejs](http://www.vedcasts.com.br/series/vuejs). 4 | 5 | ### Instruções de Instalação 6 | 7 | Usando o Terminal, clonar o projeto localmente com `git clone git@github.com:vedcasts/series-vuejs-project.git`. Acessar a pasta do projeto com `cd ` (possivelmente cd series-vuejs-project/). 8 | 9 | As bibliotecas/frameworks Javascript obrigatórias para o projeto estão listadas no arquivo `/package.json` encontrado na raiz do site. Trata-se do arquivo lido pelo NPM que fará o download do Javascript do projeto. 10 | 11 | Assim, é obrigatório ter o Node.js/NPM instalados. Sua instalação é simples e está disponível para todos os principais sistemas operacionais. Mais info [http://www.nodejs.org](http://www.nodejs.org). 12 | 13 | Após certificar-se de que seu ambiente atende aos pré-requisitos listados logo acima, basta usar o Terminal para navegar até a pasta do projeto e rodar o comando `npm install`. Isso criará a pasta /node_modules na raiz do projeto e ali armazenará os scripts necessários. 14 | 15 | **Muito importante !!!** 16 | A série foi desenvolvida utilizando a versão 0.12.* fo Vue.js. Logo após a publicação dos videos a versão 1.0 foi lançada e uma aula tratando exclusivamente do processo de upgrade foi disponibilizada: aula 22. Para ter acesso ao código fonte das aulas 1 a 21 utilize o branch **vue0.12.x**. Para o código fonte atualizado com a versão 1.0.x utilize o branch **master**. 17 | 18 | ### Scripts to projeto 19 | 20 | Os arquivos principais são index.html e app.js. 21 | 22 | ### Dúvidas e sugestões 23 | 24 | Por gentileza assista às aulas e deixe suas dúvidas ou sugestões no sistema de comentários existente em cada página de videos. -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Vue filter estará a disposição no HTML. Exemplo: 4 | *

{{ cervejaria.last_mod | dateFormat }}

5 | * Documentação oficial sobre filters: http://vuejs.org/guide/filters.html 6 | */ 7 | Vue.filter('dateFormat', function(value, formatString) 8 | { 9 | if(formatString != undefined) 10 | { 11 | return moment(value).format(formatString); 12 | } 13 | return moment(value).format('DD/MM/YYYY'); 14 | }); 15 | 16 | new Vue({ 17 | 18 | /** 19 | * Element HTML que será gerenciado 20 | */ 21 | el: '#beerApp', 22 | 23 | /** 24 | * Todas as propriedades deste objeto estará disponíveis 25 | * no HTML de ID beerApp e seus filhos. Qualquer mudança 26 | * nos valores do objeto será refletida no HTML. 27 | */ 28 | data: { 29 | cervejaria: { 30 | name: '', 31 | city: '', 32 | state: '', 33 | country: '', 34 | descript: '' 35 | }, 36 | cervejarias: { 37 | all: [], 38 | list: [], 39 | paginated: [] 40 | }, 41 | pagination: { 42 | perPage: 8, 43 | currentPage: 1, 44 | totalPages: 0, 45 | totalItems: 0, 46 | pageNumbers: [], 47 | visibleNumbers: 3 48 | }, 49 | interaction: { 50 | visibleColumns: ['name', 'last_mod'], 51 | columnsToFilter: [], 52 | filterTerm: '', 53 | openDetails: [], 54 | sortColumn: 'name', 55 | sortInverse: 0, 56 | }, 57 | controls: { 58 | select2: null, 59 | } 60 | }, 61 | 62 | /** 63 | * Os métodos abaixo estarão disponíveis no HTML 64 | * de ID beerApp e seus filhos 65 | */ 66 | methods: { 67 | 68 | edit: function(ev, cervejaria) 69 | { 70 | ev.preventDefault(); 71 | 72 | this.cervejaria.name = cervejaria.name; 73 | this.cervejaria.city = cervejaria.city; 74 | this.cervejaria.state = cervejaria.state; 75 | this.cervejaria.country = cervejaria.country; 76 | this.cervejaria.descript = cervejaria.descript; 77 | 78 | jQuery(this.$els.modal).modal('show'); 79 | }, 80 | 81 | save: function(ev) 82 | { 83 | ev.preventDefault(); 84 | 85 | // this.$http.post('url do servico', cervejaria, function(response) 86 | // { 87 | 88 | // }); 89 | 90 | jQuery(this.$els.modal).modal('hide'); 91 | window.alert('Cervejaria salva, seu bebum!'); 92 | window.console.log(JSON.stringify(this.cervejaria)); 93 | }, 94 | 95 | new: function() 96 | { 97 | this.cervejaria.name = ''; 98 | this.cervejaria.city = ''; 99 | this.cervejaria.state = ''; 100 | this.cervejaria.country = ''; 101 | this.cervejaria.descript = ''; 102 | 103 | jQuery(this.$els.modal).modal('show'); 104 | }, 105 | 106 | setPaginationData: function(list) 107 | { 108 | var self = this, 109 | chunk = _.chunk(list, self.pagination.perPage); 110 | 111 | Vue.set(self.cervejarias, 'paginated', chunk); 112 | Vue.set(self.cervejarias, 'list', chunk[0]); 113 | 114 | Vue.set(self.pagination, 'currentPage', 1); 115 | Vue.set(self.pagination, 'totalItems', list.length); 116 | Vue.set(self.pagination, 'totalPages', Math.ceil(list.length / self.pagination.perPage)); 117 | Vue.set(self.pagination, 'pageNumbers', _.range(1, self.pagination.totalPages+1)); 118 | }, 119 | 120 | page: function(ev, page) 121 | { 122 | ev.preventDefault(); 123 | 124 | var self = this; 125 | 126 | Vue.set(self.pagination, 'currentPage', page); 127 | 128 | Vue.set(self.cervejarias, 'list', self.cervejarias.paginated[page-1]); 129 | }, 130 | 131 | next: function(ev) 132 | { 133 | ev.preventDefault(); 134 | 135 | var self = this; 136 | 137 | if(self.pagination.currentPage == self.pagination.totalPages) 138 | { 139 | return false; 140 | } 141 | 142 | Vue.set(self.pagination, 'currentPage', self.pagination.currentPage+1); 143 | 144 | Vue.set(self.cervejarias, 'list', self.cervejarias.paginated[self.pagination.currentPage-1]); 145 | }, 146 | 147 | previous: function(ev) 148 | { 149 | ev.preventDefault(); 150 | 151 | var self = this; 152 | 153 | if(self.pagination.currentPage == 1) 154 | { 155 | return false; 156 | } 157 | 158 | Vue.set(self.pagination, 'currentPage', self.pagination.currentPage-1); 159 | 160 | Vue.set(self.cervejarias, 'list', self.cervejarias.paginated[self.pagination.currentPage-1]); 161 | }, 162 | 163 | doResetAll: function() 164 | { 165 | var self = this; 166 | 167 | Vue.set(self.interaction, 'visibleColumns', ['name', 'last_mod']); 168 | Vue.set(self.interaction, 'columnsToFilter', []); 169 | Vue.set(self.interaction, 'filterTerm', ''); 170 | Vue.set(self.interaction, 'openDetails', []); 171 | Vue.set(self.interaction, 'sortColumn', 'name'); 172 | Vue.set(self.interaction, 'sortInverse', 0); 173 | 174 | self.setPaginationData(self.cervejarias.all); 175 | 176 | self.controls.select2.val('').trigger('change'); 177 | }, 178 | 179 | doFilter: function() 180 | { 181 | var self = this, 182 | filtered = self.cervejarias.all; 183 | 184 | if(self.interaction.filterTerm != '' && self.interaction.columnsToFilter.length > 0) 185 | { 186 | filtered = _.filter(self.cervejarias.all, function(cervejaria) 187 | { 188 | return self.interaction.columnsToFilter.some(function(column) 189 | { 190 | return cervejaria[column].toLowerCase().indexOf(self.interaction.filterTerm.toLowerCase()) > -1 191 | }); 192 | }); 193 | } 194 | 195 | self.setPaginationData(filtered); 196 | }, 197 | 198 | doSort: function(ev, column) 199 | { 200 | ev.preventDefault(); 201 | 202 | var self = this; 203 | 204 | self.interaction.sortColumn = column; 205 | 206 | if(self.interaction.sortInverse == 0) 207 | { 208 | Vue.set(self.interaction, 'sortInverse', -1); 209 | } else { 210 | Vue.set(self.interaction, 'sortInverse', 0); 211 | } 212 | }, 213 | 214 | doOpenDetails: function(ev, id) 215 | { 216 | ev.preventDefault(); 217 | 218 | var self = this, 219 | 220 | index = self.interaction.openDetails.indexOf(id); 221 | 222 | if(index > -1) 223 | { 224 | self.interaction.openDetails.$remove(id); 225 | } else { 226 | self.interaction.openDetails.push(id); 227 | } 228 | }, 229 | 230 | openAllDetails: function(ev) 231 | { 232 | ev.preventDefault(); 233 | 234 | var self = this; 235 | 236 | if(self.interaction.openDetails.length > 0) 237 | { 238 | Vue.set(self.interaction, 'openDetails', []); 239 | } else { 240 | Vue.set(self.interaction, 'openDetails', _.pluck(self.cervejarias.list, 'id')); 241 | } 242 | } 243 | }, 244 | 245 | /** 246 | * Este método será executado assim que tanto o Vue quanto 247 | * o HTML de ID beerApp (e seus filhos) estiverem prontos. 248 | */ 249 | ready: function() 250 | { 251 | var self = this; 252 | 253 | /** 254 | * Para distribuição foi adicionado ao projeto o arquivo 255 | * cervejarias.json, contendo todos os dados necessários 256 | * para a aplicação funcionar corretamente. Não funciona 257 | * se você abrir a página index.html no browser utilizando 258 | * Ctrl (CMD) + o. É preciso um virtual host. 259 | * Solução: coloque o arquivo em algum de seus domínios para poder 260 | * usar abaixo: http://www.seudominio.com/cervejarias.json. 261 | */ 262 | self.$http.get('/cervejarias.json', function(response) 263 | // self.$http.get('http://api.beer.app/cervejarias', function(response) 264 | { 265 | Vue.set(self.cervejarias, 'all', response); 266 | 267 | self.setPaginationData(response); 268 | }); 269 | 270 | self.controls.select2 = jQuery(self.$els.columnsToFilterSelect).select2({ 271 | placeholder: 'Selecionar uma ou mais colunas para filtrar!' 272 | }).on('change', function() 273 | { 274 | Vue.set(self.interaction, 'columnsToFilter', jQuery(this).val() || []); 275 | }); 276 | } 277 | }); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 53 |
54 | 55 |

Bem vindo à série Vue.js!

56 | 57 | 60 | 61 |
62 |
63 |
64 | 65 | 75 |
76 | 77 |
78 | 83 |
84 | 85 |
86 | 91 |
92 |
93 |
94 |
95 |
96 |
97 | 103 |
104 |
105 | 115 |
116 |
117 |
118 | 119 | 120 | 121 | 122 | 130 | 138 | 146 | 154 | 162 | 171 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 196 | 199 | 200 | 201 | 202 | 203 | 204 |
123 | 128 | Nome 129 | 131 | 136 | Cidade 137 | 139 | 144 | Estado 145 | 147 | 152 | País 153 | 155 | 160 | Atualizado em 161 | 163 | 164 | 169 | 170 | 172 | 173 |
{{ cervejaria.name }}{{ cervejaria.city }}{{ cervejaria.state }}{{ cervejaria.country }}{{ cervejaria.last_mod | dateFormat 'DD/MM/YYYY HH:mm:ss' }} 184 | 187 | 191 | 192 | 195 | 197 | 198 |
{{ cervejaria.descript }}
205 | 206 | 226 | 227 | 230 |
231 |
232 |
233 | 234 |
235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 |
244 | 245 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VueSeries", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bootstrap": "^3.3.5", 13 | "font-awesome": "^4.4.0", 14 | "jquery": "^2.1.4", 15 | "lodash": "^3.10.1", 16 | "moment": "^2.10.6", 17 | "select2": "^4.0.0", 18 | "vue": "^1.0.0", 19 | "vue-resource": "^0.1.15" 20 | } 21 | } 22 | --------------------------------------------------------------------------------