Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
12
respostas

Criar uma Modal como Diretiva

Olá pessoal, estou tendo algumas dificuldades para criar uma Modal como uma Diretiva, onde a ideia seria criar uma modal para confirmar uma determinada ação, possuindo dois botões, um de Sim e outro de Não e, para cada um destes dois botões atribuir uma função.

No treinamento, foi mostrado o uso do caractere "&" (utilizado quando queremos executar dentro de uma diretiva uma função que pertence a um escopo pai, o de um controller), porém não está funcionado.

A modal até está aparecendo, quando chamo ela através de um botão que adicionei na view, porém, as ações não são executadas.

Abaixo segue os códigos:

<!-- View Principal -->

<div class="row">
    <div class="col-md-12">
        <button class="btn btn-block bg-primary" type="button" ng-click="showModal()">Chama Modal</button>
    </div>
</div>

<!-- Invocação da modal na View Principal quando variável show = true -->

<div class="row">
    <minha-modal show="show" title="Minha Modal" confirmAction="clicouBotaoSim()" cancelAction="clicouBotaoNao()">
        Deseja realmente excluir?
    </minha-modal>
</div>

<!-- Controller View -->

$scope.showModal = function()
    {
        $scope.show = true;
    };

    $scope.clicouBotaoSim = function()
    {
        console.log("SIM");
    };

    $scope.clicouBotaoNao = function()
    {
        console.log("NAO");
    };

<!-- Diretiva -->

.directive('minhaModal', function() {

        var ddo = {};

        ddo.restrict = "E";

        ddo.transclude = true;

        ddo.scope = {
            show:          "=",
            title :        "@",
            confirmAction: "&",
            cancelAction:  "&"
        };

        ddo.templateUrl = "js/directives/minha-modal.html";

        return ddo;

    });

<!-- Template Diretiva -->

<div class='ng-modal' ng-show='show'>

    <div class='ng-modal-overlay' ng-click='cancelAction()'></div>

    <div class='ng-modal-dialog' ng-style='dialogStyle'>

        <div class="modal-content">

            <div class="modal-header">
                <button type="button" class="close" ng-click="cancelAction()">&times;</button>
                <h3 class="modal-title">{{title}}</h3>
            </div>

            <div class="modal-body">
                <p ng-transclude></p>
            </div>

            <div class="modal-footer">
                <div class="row">
                    <div class="col-md-6 col-xs-6">
                        <button type="button" ng-click="confirmAction()" class="btn btn-success col-md-4 col-xs-6">
                            Sim
                        </button>
                    </div>
                    <div class="col-md-6 col-xs-6">
                        <button type="button" ng-click="cancelAction()" class="btn btn-danger col-md-4 col-xs-6 col-md-offset-8 col-xs-offset-6">
                            Não
                        </button>
                    </div>
                </div>
            </div>

        </div>

    </div>

</div>

<!-- CSS utilizado para a Modal -->

.ng-modal-overlay {
    /* A dark translucent div that covers the whole screen */
    position: absolute;
    z-index: 9999;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #000000;
    opacity: 0.8;
}
.ng-modal-dialog {
    /* A centered div above the overlay with a box shadow. */
    z-index: 10000;
    position: absolute;
    width: 50%; /* Default */

    /* Center the dialog */
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    -webkit-transform: translate(-50%, -50%);
    -moz-transform: translate(-50%, -50%);

    background-color: #fff;
    box-shadow: 4px 4px 80px #000;
}
.ng-modal-dialog-content {
    padding: 10px;
    text-align: left;
}
.ng-modal-close {
    position: absolute;
    top: 3px;
    right: 5px;
    padding: 5px;
    cursor: pointer;
    font-size: 120%;
    display: inline-block;
    font-weight: bold;
    font-family: 'arial', 'sans-serif';
}

Desde já agradeço!

12 respostas

O console.log é exibido ? Tem Log do Chrome. Qual versão angular está usando?

No console não é exibido absolutamente nada. A versão do Angular é v1.3.15.

Você precisa colar todo o seu código, não pinçado como você fez. Aguardo seu feedback.

Por exemplo, na view principal, não tenho como saber se você associou o controller corretamente. Um fórum legal específico de Angular para pedir ajuda também é o

https://www.facebook.com/groups/angularjsbrasil

Segue códigos completos.

<!-- View Principal ->>

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

<p class="alert alert-info" ng-show="mensagem.length">
    {{mensagem}}
</p>

<div class="row">
    <div class="col-md-12">
        <form>
            <div class="input-group">
                <span class="input-group-btn">
                    <a href="fotos/new" class="btn btn-primary">Nova Foto</a>
                </span>
                <input class="form-control" ng-model="filtro" ng-model-options="{ debounce: 500 }" placeholder="filtrar" />
            </div>
        </form>
    </div>
</div>

<br>

<div class="row">
    <meu-painel class="col-md-2 .painel-animado" ng-repeat="foto in fotos | filter:filtro" titulo="{{foto.titulo}}">
        <minha-foto url="{{foto.url}}" titulo="{{foto.titulo}}"></minha-foto>
        <a href="/fotos/edit/{{foto._id}}" class="btn btn-primary btn-block">Editar</a>
        <meu-botao-perigo nome="Remover" acao="remover(foto)"></meu-botao-perigo>
    </meu-painel>
</div>

<div class="row">
    <div class="col-md-12">
        <button class="btn btn-block bg-primary" type="button" ng-click="showModal()">Chama Modal</button>
    </div>
</div>

<div class="row">
    <minha-modal show="show" title="Minha Modal" confirmAction="clicouBotaoSim()" cancelAction="clicouBotaoNao()">
        Deseja realmente excluir?
    </minha-modal>
</div>

<!-- Controller View Principal -->>

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

    $scope.fotos    = [];
    $scope.filtro   = "";
    $scope.mensagem = "";
    $scope.show     = false;

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

    $scope.remover = function(foto)
    {
        recursoFoto.delete({fotoId: foto._id},
            function() {
                var indiceFoto = $scope.fotos.indexOf(foto);
                $scope.fotos.splice(indiceFoto, 1);
                $scope.mensagem = 'Foto ' + foto.titulo + ' foi removida com sucesso';
            },
            function(error) {
                console.log(error);
                $scope.mensagem = 'Não foi possível remover a foto ' + foto.titulo;
            }
        );
    };

    $scope.showModal = function()
    {
        $scope.show = true;
    };

    $scope.clicouBotaoSim = function()
    {
        console.log("SIM");
    };

    $scope.clicouBotaoNao = function()
    {
        console.log("NAO");
    };

});

<!-- Diretiva -->>

angular.module('minhasDiretivas', [])
    .directive('meuPainel', function()
    {

        var ddo = {};

        ddo.restrict = "AE";
        ddo.transclude = true;


        ddo.scope = {
            titulo: '@'
        };

        ddo.templateUrl = 'js/directives/meu-painel.html';

        return ddo;
    })

    .directive('minhaFoto', function()
    {
        var ddo = {};

        ddo.restrict = "AE";

        ddo.scope = {
            titulo: '@',
            url:    '@'
        };

        ddo.template = '<img class="img-responsive center-block" src="{{url}}" alt="{{titulo}}">';

        return ddo;
    })

    .directive('meuBotaoPerigo', function() {

        var ddo = {};

        ddo.restrict = "E";

        ddo.scope = {
            nome:  '@',
            acao : '&'
        };

        ddo.template = '<button class="btn btn-danger btn-block" ng-click="acao()">{{nome}}</button>';

        return ddo;

    })

    .directive('minhaModal', function() {

        var ddo = {};

        ddo.restrict = "E";

        ddo.transclude = true;

        ddo.scope = {
            show:          "=",
            title :        "@",
            confirmAction: "&",
            cancelAction:  "&"
        };

        ddo.templateUrl = "js/directives/minha-modal.html";

        return ddo;

    })

    .directive('meuFocus', function() {

        var ddo = {};

        ddo.restrict = "A";

        ddo.link = function(scope, element)
        {
            scope.$on('fotoCadastrada', function() {
                element[0].focus();
            });
        };

        return ddo;

    })

    .directive('meusTitulos', function() {

        var ddo = {};

        ddo.restrict = "E";

        ddo.template = '<ul><li ng-repeat="titulo in titulos">{{titulo}}</li></ul>';

        ddo.controller = function($scope, recursoFoto)
        {
            recursoFoto.query(function(fotos)
            {
                $scope.titulos = fotos.map(function(foto) {
                    return foto.titulo;
                });
            });
        };

        return ddo;

    }
);

<!-- Template Modal -->

<div class='ng-modal' ng-show='show'>

    <div class='ng-modal-overlay' ng-click='cancelAction()'></div>

    <div class='ng-modal-dialog' ng-style='dialogStyle'>

        <div class="modal-content">

            <div class="modal-header">
                <button type="button" class="close" ng-click="cancelAction()">&times;</button>
                <h3 class="modal-title">{{title}}</h3>
            </div>

            <div class="modal-body">
                <p ng-transclude></p>
            </div>

            <div class="modal-footer">
                <div class="row">
                    <div class="col-md-6 col-xs-6">
                        <button type="button" ng-click="confirmAction()" class="btn btn-success col-md-4 col-xs-6">
                            Sim
                        </button>
                    </div>
                    <div class="col-md-6 col-xs-6">
                        <button type="button" ng-click="cancelAction()" class="btn btn-danger col-md-4 col-xs-6 col-md-offset-8 col-xs-offset-6">
                            Não
                        </button>
                    </div>
                </div>
            </div>

        </div>

    </div>

</div>

Segue o main das rotas.


angular.module('alurapic', ['minhasDiretivas', 'ngAnimate', 'ngRoute', 'meusServicos'])
    .config(function($routeProvider, $locationProvider) {

        $locationProvider.html5Mode(true);

        $routeProvider.when('/fotos', {
            templateUrl: 'partials/principal.html',
            controller:  'FotosController'
        });

        $routeProvider.when('/fotos/new', {
            templateUrl: 'partials/foto.html',
            controller:  'FotoController'
        });

        $routeProvider.when('/fotos/edit/:fotoId', {
            templateUrl: 'partials/foto.html',
            controller:  'FotoController'
        });

        $routeProvider.otherwise({
            redirectTo: '/fotos'
        });

    }
);

Index.html? Faltou :)

Verdade. Segue =]


<!-- index.html -->

<!DOCTYPE html>
<html lang="pt-br" ng-app="alurapic">

    <head>
        <meta charset="UTF-8">
        <base href="/">
        <meta name="viewport" content="width=device-width">
        <title>Alurapic</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <link rel="stylesheet" href="css/efeitos.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/lib/angular-animate.min.js"></script>
        <script src="js/lib/angular-route.min.js"></script>
        <script src="js/lib/angular-resource.min.js"></script>
        <script src="js/main.js"></script>
        <script src="js/controllers/fotos-controller.js"></script>
        <script src="js/controllers/foto-controller.js"></script>
        <script src="js/controllers/grupos-controller.js"></script>
        <script src="js/directives/minhas-diretivas.js"></script>
        <script src="js/services/meus-servicos.js"></script>
    </head>

    <body>

        <div class="container">

            <ng-view></ng-view>

        </div>

    </body>

</html>

Eu agora estou entrando em sala de aula, mas eu já peguei seu código. Vou deixar aqui em aberto para ver se algum colega o ajuda (sem ter que me esperar). Ainda hoje, dou uma posição sobre ele Fernando. Tudo bem? Já entendi melhor o que você quer.

Oi Flávio, ok, sem problemas.

solução!

Olá Fernando, agora que eu consegui respirar dei uma olhada no seu código e descobri o problema. A teoria você pegou muito bem, seu código está 99.9999% correto. Onde você errou?

O nome da sua diretiva é minhaModal e você sabiamente usa a diretiva no seu html como <minha-modal>. Você trocou o CamelCase por hífen.

O problema é que você esqueceu de trocar para hífen no restante das propriedades da diretiva. Hoje está assim:

    <minha-modal show="show" title="Minha Modal" confirmAction="clicouBotaoSim()" cancelAction="clicouBotaoNao()">
        Deseja realmente excluir?
    </minha-modal>

O certo é

    <minha-modal show="show" title="Minha Modal" confirm-action="clicouBotaoSim()" cancel-action="clicouBotaoNao()">
        Deseja realmente excluir?
    </minha-modal>

Também nos nomes das propriedades usamos hífen.

Bom estudo meu aluno e feliz 2016!

Oi Flávio,

muito obrigado pela sua atenção. Realmente, utilizei o hífen nas propriedades e funcionou perfeitamente.

Agora está funcionando 100% minha diretiva.

Abraço!