Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Ação Desfazer

É possível criar uma ação "desfazer" usando esta estrutura atual do projeto?

6 respostas

Pode dar um exemplo mais concreto?

Como no do gmail por exemplo, ao invés de confirma uma ação. ele permite realizar, mas depois você pode desfazer, como um ctrl + z no Windows por exemplo.

Mesmo que seja apenas no DOM, sem conexão com o banco (se for com conexão com o banco no exemplo do curso, melhor ainda).

Vou ter em mente o seu exemplo do gmail, ok?

Nunca precisei implementar isso, mas talvez um caminho seja usar o serviço $timeout que é um wrapper para o setTimeout do JavaScript. Mas você precisa ter um cuidado GIGANTE com ele, porque ele tem os mesmos problemas do setTimeout. Sendo assim, veja que Angular é apenas um framework e que conhecer a linguagem JavaScript é fundamental para resolver problemas como esse.

solução!

Achei sua necessidade curiosa. Implementei uma solução como prova de conceito para te dar um norte a seguir (eu como usuário gostaria de ter esse recurso).

Eu alterei o projeto final do curso. No caso, coloquei a opção de desfazer para a remoção de fotos. Quando você clicar em remover, terá 3 segundos para desistir da operação. Mas isso é só prova de conceito, por exemplo, se o usuário realizar outra operação nesse tempo do desfazer? Ai você tem que decidir o que vai fazer.

Primeiro, segue a parcial principal.html alterada para exibir o botão desfazer:

<div class="jumbotron">
    <h1 class="text-center">Alurapic</h1>
</div>

<button ng-show="exibeBotaoDesfazer" class="btn btn-default" ng-click="desfazer()" >Desfazer</button>
<!-- código posterior omitido -->

Veja que o botão só é exibir se exibeBotaoDesfazer em $scopedo controller for true. E quando o usuário clica em desfazer ele realiza a operação. Agora, vamos para nosso controller.

// FotosController.js
/*
Veja que eu injeto o serviço `$timeout` para poder executar uma operação depois de tantos segundos.

*/
angular.module('alurapic').controller('FotosController', function($scope, recursoFoto, $timeout) {

    $scope.fotos = [];
    $scope.filtro = '';
    $scope.mensagem = '';

    recursoFoto.query(function(fotos) {
        $scope.fotos = fotos;
    }, function(erro) {
        console.log(erro);
    });

    $scope.remover = function(foto) {


        // quando remover é chamado, eu exibo o botão `desfazer` colocando true na propriedade abaixo:

        $scope.exibeBotaoDesfazer = true;

        // aqui que vem a malandragem. Eu digo que a remoção só será realizada depois de 3 segundos. Se antes desse tempo alguém clicar em desfazer, vai cancelar o envio do pedido de exclusão para o servidor.

        // ATENÇÃO: EU GUARDO O RETORNO DE $timeout em uma propriedade do controller. É ela que me possibilita cancelar o timeout, pois tem uma referência para ele.
        $scope.timeout = $timeout(function() {

            recursoFoto.delete({fotoId: foto._id}, function() {

                // Você concorda que se os 3 segundos acabam é porque meu código foi executado e como o tempo acabou eu não posso mais exibir o botão desfazer. Eu sumo bom o botão!
                $scope.exibeBotaoDesfazer = false;

                // aqui é o padrão
                var indiceDaFoto = $scope.fotos.indexOf(foto);
                $scope.fotos.splice(indiceDaFoto, 1);
                $scope.mensagem = 'Foto ' + foto.titulo + ' removida com sucesso!';
            }, function(erro) {
                console.log(erro);
                $scope.mensagem = 'Não foi possível apagar a foto ' + foto.titulo;
            });

        }, 3000); // veja que o $timeout recebe uma função e o segundo parâmetro o tempo em milisegundos

    };

    // aqui é nosso método que desfaz:
    $scope.desfazer = function() {

        // eu chamo o serviço $timeout.cancel que precisa receber uma referência do timer que criamos. Lembre-se que guardamos a referência em $scope.timeout    
        $timeout.cancel($scope.timeout);
        $scope.mensage = 'Operação desfeita com sucesso';
        $scope.exibeBotaoDesfazer = false;
    }
});

O código funciona e pode ser uma luz nessa problemática que você quer resolver. Só não sei que pode ter algum efeito colateral mais sério. Até gostei de bolar essa solução :)

Show!!!! Por isso eu assinei o Alura! Vlw mesmo.

Vou implementar isso, e assim que o fizer, mando o link =D

Beleza, mas tipo, a coisa é mais complexa. Se o usuário clicar em desfazer em três fotos rapidamente? Do jeito que está, ele só conseguirá cancelar a última. Então tem que pensar a UX do cara direitinho.

Conseguindo implementar essa solução, me dá um feedback para a gente marcar esse post como resolvido.