Aplicativo Desktop com Nwjs + AngularJS + Bootstrap + Sqlite
Olá pessoal, hoje faremos um aplicativo desktop simples para cadastro de pessoas, usando nwjs, AngularJS, Bootstrap e o banco de dados Sqlite. Veja aqui como fazer um aplicativo com nwjs, executar e empacotar.
Downloads
Para iniciar faça download das tecnologias necessárias:
- Bootstrap
- Node-webkit (nwjs)
- SQLiteStudio (Você pode usar outro SGBD se preferir)
As demais dependências serão instaladas com NPM.
Estrutura de pastas e arquivos
Agora faremos a estrutura de pastas e arquivos da nossa aplicação.
Banco de dados
Abra o SQLiteStudio, crie um banco de dados salvando o arquivo na pasta model da sua aplicação com o nome database.db.
Conectado ao banco de dados crie a seguinte tabela:
CREATE TABLE pessoas ( id INTEGER PRIMARY KEY AUTOINCREMENT, nome CHAR (100), email CHAR (100), nascimento DATE, endereco CHAR (200), ativo INT DEFAULT (1) );
Usaremos o campo ativo para informar se a pessoa está ativa ou não, se não está ativa está excluída.
Instalando pacotes
Para iniciar, deixaremos o arquivo package.json da seguinte maneira:
package.json
Feito isso, abra o terminal navegue usando cd até o diretório da aplicação e execute o seguinte comando: npm install
index.html
Este arquivo será o principal da nossa aplicação, e deve ter o seguinte conteúdo:
<html ng-app="cdg"> <head> <title>Clube dos Geeks</title> <link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.css"> <!-- jQuery --> <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script> <!-- Bootstrap --> <script src="bootstrap/js/bootstrap.js"></script> <!-- Angular --> <script src="node_modules/angular/angular.js"></script> <!-- Angular - Pagination --> <script src="node_modules/angular-utils-pagination/dirPagination.js"></script> <!-- App --> <script src="app.js"></script> <!-- Controllers --> <script src="controllers/pessoaController.js"></script> <!-- Services --> <script src="services/dbService.js"></script> </head> <body> <!-- Menu --> <nav class="navbar navbar-default"> <div class="container-fluid"> <div class="navbar-header"> <a class="navbar-brand" href="#/"> Clube dos Geeks </a> </div> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li> <a href="#/pessoas">Pessoas</a> </li> </ul> </div> </div> </nav> <!-- Onde será carregada a view --> <div ng-view="" class="container"></div> <!-- Rodapé --> <nav class="navbar navbar-default navbar-fixed-bottom"> <div class="container"> <ul class="nav navbar-nav"> <li> <a href="//clubedosgeeks.com.br">Clube dos Geeks</a> </li> <li> <a href="//jayralencar.com.br">Jayr Alencar</a> </li> </ul> </div> </nav> </body> </html>
Observe que na linha 1, usamos o atributo ng-app, que serve para instanciar a aplicação, para que o angular possa trabalhar.
app.js
Criaremos agora o arquivo responsável por iniciar e direcionar as rotas do angular, veja:
var app = angular.module('cdg', [require('angular-route'),'angularUtils.directives.dirPagination']); app.config(function($routeProvider){ $routeProvider.when("/pessoas", { templateUrl : "views/pessoa.html", controller : "pessoaController", access: { requiredLogin: false } }); });
services/dbService.js
Este arquivo será responsável pela conexão com o banco de dados, busca e consolidação das informações.
Como a biblioteca para SQLite – desenvolvida por nós – já tem funções de inserção e edição que facilita as querys, este service irá retornar apenas a instância da biblioteca. Veja:
"USE STRICT"; app.factory("dbService", function($http){ var sqlite = require('sqlite-sync'); var db = sqlite.connect('model/database.db'); return db; });
controllers/pessoaControllers.js
Este arquivo, como o nome sugere, faz o controle da view, trata as informações, busca e salva no banco de dados.
Como você provavelmente vai querer criar outros CRUD’s, deve tomar esse controller como base para os outros, assim como a view, que falaremos mais abaixo.
Veja o arquivo:
"USE STRICT"; app.controller("pessoaController", function($scope, $location, dbService){ //Listando $scope.listaPessoas = function(){ dbService.runAsync("SELECT * FROM pessoas WHERE ativo = 1", function(data){ $scope.pessoas = data; }); } //Salvando $scope.salvar = function(){ if($scope.pessoa.id){ //Editar var id = $scope.pessoa.id; delete $scope.pessoa.id; delete $scope.pessoa.$$hashKey; //Apaga elemento $$hashKey do objeto dbService.update('pessoas', $scope.pessoa, {id: id}); //entidade, dados, where }else{ //nova dbService.insert('pessoas', $scope.pessoa); // entidade, dados } $scope.pessoa = {}; $scope.listaPessoas(); $('#modalPessoa').modal('hide'); } //Abrindo para editar $scope.editar = function(dados){ $scope.pessoa = dados; $('#modalPessoa').modal('show'); } //Excluindo $scope.excluir = function(dados){ if(confirm("Deseja realmente apagar o cadastro de "+dados.nome+"?")){ dbService.update('pessoas', {ativo:0}, {id: dados.id}); $scope.listaPessoas(); } } });
views/pessoa.html
Agora, na pasta views criaremos nosso arquivo de visão, onde os dados serão mostrados.
Aqui nos usamos a diretiva dirPagination para fazer e a paginação dos dados na tabela. Veja:
<div class="row"> <div class="col-md-8"> <button class="btn btn-primary" data-toggle="modal" data-target="#modalPessoa"><span class="glyphicon glyphicon-plus"></span> Nova Pessoa</button> </div> <div class="col-md-4"> <input class="form-control" placeholder="Pesquisar" ng-model="pesquisar"> </div> </div> <hr> <div class="row"> <div class="col-md-12"> <table class="table table-striped" ng-init="listaPessoas()"> <thead> <th>#</th> <th>Nome</th> <th>E-mail</th> <th>Endereço</th> <th>Nascimento</th> <th></th> </thead> <tbody> <!-- Listagem --> <tr dir-paginate="pessoa in pessoas|filter:pesquisar|itemsPerPage:8"> <td>{{pessoa.id}}</td> <td>{{pessoa.nome}}</td> <td>{{pessoa.email}}</td> <td>{{pessoa.endereco}}</td> <td>{{pessoa.nascimento}}</td> <td> <button class="btn btn-info btn-xs" ng-click="editar(pessoa)"><span class="glyphicon glyphicon-pencil"></span> Editar</button> <button class="btn btn-danger btn-xs" ng-click="excluir(pessoa)"><span class="glyphicon glyphicon-trash"></span> Excluir</button> </td> </tr> </tbody> </table> </div> </div> <!-- Paginação --> <div class="row"> <div class="col-md-12 text-center"> <dir-pagination-controls> </dir-pagination-controls> </div> </div> <!-- Modal Cadastro e Edição --> <div class="modal fade" id="modalPessoa" tabindex="-1" role="dialog" > <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Pessoa</h4> </div> <div class="modal-body"> <div class="row"> <div class="col-md-6"> <label>Nome</label> <input class="form-control" type="text" ng-model="pessoa.nome"> </div> <div class="col-md-6"> <label>E-mail</label> <input class="form-control" type="text" ng-model="pessoa.email"> </div> </div> <div class="row"> <div class="col-md-6"> <label>Data de Nascimento</label> <input class="form-control" type="text" ng-model="pessoa.nascimento"> </div> <div class="col-md-6"> <label>Endereço</label> <input class="form-control" type="text" ng-model="pessoa.endereco"> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" ng-click="pessoa = {}" data-dismiss="modal">Cancelar</button> <button type="button" class="btn btn-primary" ng-click="salvar()">Salvar</button> </div> </div> </div> </div>
Executando
Se você não sabe como executar ou gerar o .exe, Veja aqui
GitHub
Este exemplo está disponível do GitHub também, veja.
Prévia
Muito bom, parabéns!!! Simples e útil…
Olá amigo tudo bem, muito bom este tutorial bem detalhado, eu queria só tirar uma duvida, se esta aplicação é necessário rodar online, eu sei que fica local, mas é necessario a pessoa ter conexão com Internet para funcionar o banco de dados e as demais requisições? Obrigado e sucesso!
Opa Hille. Nessa aplicação não é necessário, a única coisa que precisa de conexão nela é o jQuery que é puxado da internet, o que vou mudar em breve.
Mas você pode sim conectar ela com um banco na nuvem, ou com uma API RESTful de preferência.
Depois que gero o executavel, no linux ou win, é possível pegar o fonte? Digo por questão de segurança na distribuição de um projeto pago.
Opa Romulo, até onde eu sei não. Dei uma olhada na internet e nas issues do projeto nwjs no git hub e não vi nada a respeito.
Publiquei a seguinte Issues no projeto: https://github.com/nwjs/nw.js/issues/4608
Acompanhe.
Sei que como o webkit é um browser serão criados vários arquivos e pastas em %LOCALAPPDATA% (em caso de windows). Mas nada referente a arquivos .html ou .js por exemplo.
Muito bom o artigo bem explicado, parabéns!
Agora está dando erro no “require(‘angular-route’)”
Uncaught ReferenceError: require is not defined(anonymous function) @ app.js:1
pessoaController.js:2 Uncaught TypeError: Cannot read property ‘controller’ of undefined(anonymous function) @ pessoaController.js:2
pode me ajudar?
Oi Wesley, você executou o comando npm install?
Se sim tente executar npm install angular-route para instalar o módulo em questão.
Verifique se ocorre algum erro durante a instalação.
executei sim!
após executar o comando sugerido aparece a seguinte mensagem:
C:\Users\wesley_oliveira\WebstormProjects\momadesAppDesktop>npm install angular-route
nwjs-angular@1.0.0 C:\Users\wesley_oliveira\WebstormProjects\momadesAppDesktop
└── angular-route@1.5.2
npm WARN EPACKAGEJSON nwjs-angular@1.0.0 No repository field.
e o erro persiste!
Uncaught ReferenceError: require is not defined
pessoaController.js:2 Uncaught TypeError: Cannot read property ‘controller’ of undefined
dbService.js:2 Uncaught TypeError: Cannot read property ‘factory’ of undefined
angular.js:4547 Uncaught Error: [$injector:modulerr] Failed to instantiate module cdg due to:
Error: [$injector:nomod] Module ‘cdg’ is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Faça o seguinte Wesley. Acesse esse link https://github.com/ClubeDosGeeksCoding/nwjs-angularjs-sqlite
Execute os comandos listados lá.
Depois acesse este http://clubedosgeeks.com.br/programacao/node-js/node-js-desenvolvendo-aplicacoes-desktop-com-node-webkit e veja como executar o programa.
Se vc seguir esses passos não tem como dar erro.
ok, deu certo!
Muito obrigado
Bom dia!
Estou com mesmo problema.
\nwjs-angularjs-sqlite\app.js:1
(function (exports, require, module, __filename, __dirname) { var app = angular.module(‘cdg’, [require(‘angular-route’),’angularUtils.directives.dirPagination’]);
^
ReferenceError: angular is not defined
at Object. (C:\Users\Philipe-TI\node-webk-32\projetos\p07\nwjs-angularjs-sqlite\app.js:1:81)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3
Tem certeza que seguiu todos os passos?
Bom dia.
Parabéns pelo tutorial,
Ao executar o comando npm install, estou tendo o segundo retorno:
npm WARN nwjs-angular@1.0.0 No repository field.
Tentei rondar no chrome e no console tenho o seguinte retorno:
pessoaController.js:2 Uncaught TypeError: Cannot read property ‘controller’ of undefined
at pessoaController.js:2
(anonymous) @ pessoaController.js:2
dbService.js:2 Uncaught TypeError: Cannot read property ‘factory’ of undefined
at dbService.js:2
O que está errado?
O erro é ao instalar o angular, tenta mudar a versão dele no arquivo package.json para 1.5.1
Troquei,
mas continua retornando o mesmo erro:
npm WARN nwjs-angular@1.5.1 No repository field.
Excelente tutorial, gracias, necesitaba este ejemplo para realizar un proyecto
Jayr se eu quiser utilizar este mesmo projeto mas para web como seria, pq tentei usar num projeto q está hospedado e ele deu erro nesse require.
Você precisa de um servidor que suporte Node.js
Mas por ser javascript o Node todas hospedagens não suportam?
Não é simplesmente JavaScript, é uma runtime que deve ser instalada no seu servidor.
Dá pra instalar o sqlite na hospedagem, posso encarar como boa notícia?
Amigo, funcionou tudo, apareceu a página index, mas ao clicar em pessoa, parece que a rota não muda, nada acontece, a tela fica simplesmente branca, tentei inclusive com o do github e deu o mesmo erro. Pode me ajudar?
Tente baixar a versão 1.5.1 do angular.
Me ajuda, eu executo o nw.exe, mas a pagina de pessoas não abre, não da nenhum erro… uso o node.js 6.13.0, aparece só o header com os menus e o rodape.
Abre o devtools pra ver se apareceu algum erro. No ícone de menu na parte esquerda superior da janela. Depois vai em Console