Solucionado (ver solução)
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!