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)
16
respostas

Curiosidade sobre Angular

Apenas por curiosidade, se eu quisesse imitar ainda mais o angular como:

Realizado em curso:

<button class="btn btn-primary text-center" onclick="negociacaoController.importarNegociacoes()" type="button">
    Importar Negociações
</button>

Trocar para:

<button class="btn btn-primary text-center" alura-controller="NegociacaoController" alura-click="importarNegociacoes()" type="button">
    Importar Negociações
</button>

Assim evitando a necessidade de instanciar o controller. É algo muito complexo de se fazer ?

16 respostas

Eu entendi o que você quer fazer, dá para fazer sim. Implementei aqui rapidinho uma solução prova de conceito:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Negociações</title>
    <link rel="stylesheet" href="css/bootstrap.css">
    <link rel="stylesheet" href="css/bootstrap-theme.css">
    <script src="js/app/polyfill/es6.js"></script>

</head>
<body class="container" data-controller="NegociacaoController">

    <!-- código omitido -->

   <!-- scripts anteriores omitidos -->
    <script>
        document.addEventListener('DOMContentLoaded', function() {

            function colocaPrimeiraLetraEmMinusculo(string) {
                        return string.charAt(0).toLowerCase() + string.slice(1);
            }

            let nodeList = document.querySelectorAll('[data-controller]');

            Reflect.apply(Array.prototype.forEach, nodeList, [function(node) {
                    let claz = node.dataset.controller;

                    let clazAsString = window.classes[claz].toString();

                    window[colocaPrimeiraLetraEmMinusculo(claz)] = new window.classes[claz]();
            });     
        });   
    </script>

</body>
</html>

Contudo, isso não é suficiente. Quando criar suas classes, você não pode tê-las no escopo global, caso contrário não conseguirá instanciá-las dimanicamente. Aqui, defini a convenção de adicionar as classes window.classes.

Vejamos como fica a declaração de `NegociacaoController':

(function(classes) {

    class NegociacaoController {

        // código omitido'
    }

    classes.NegociacaoController = NegociacaoController;

})(window.classes || (window.classes = {}));

Agora você pode filosofar um pouco sobre o código que foi escrito aí.Hehehe. Eu não fiz isso no treinamento, porque nos módulos futuros eu pretendo usar um sistema de módulo, sendo assim, essa solução é muito custosa.

A ideia do treinamento era ensinar ES6, o mini framework só nasceu porque se coadunava para explicar vários recursos do ES6. Mas eu entendo que você é um rapaz curioso. Com certeza, é sempre bom saber mais.

Fechou Matheus?

Alterei o código para usar Reflect.apply do ES6. Assim fica mais da hora!

Putz, posso simplificar ainda mais. O problema é que NodeList não possui forEach porque não é um Array e sim um NodeList. Daí, uso o spread operador para transformar o NodeList em um array:

    <script>
        document.addEventListener('DOMContentLoaded', function() {

            function colocaPrimeiraLetraEmMinusculo(string) {
                        return string.charAt(0).toLowerCase() + string.slice(1);
            }

            [...document.querySelectorAll('[data-controller]')].forEach(function(node) {
                    let claz = node.dataset.controller;

                    let clazAsString = window.classes[claz].toString();

                    window[colocaPrimeiraLetraEmMinusculo(claz)] = new window.classes[claz]();
            });     
        });   
    </script>

Só lembrando que essa solução instancia todos os controllers da sua página.

solução!

Por fim, você pode criar aluraframe/client/app/helpers/boot.js:

(function(doc, win) {

    function colocaPrimeiraLetraEmMinusculo(string) {
         return string.charAt(0).toLowerCase() + string.slice(1);
    }

    doc.addEventListener('DOMContentLoaded', function() {

        [...doc.querySelectorAll('[data-controller]')].forEach(function(node) {
                let claz = node.dataset.controller;

                let clazAsString = win.classes[claz].toString();

                win[colocaPrimeiraLetraEmMinusculo(claz)] = new win.classes[claz]();
        });     
    });   

})(document, window);

Com isso, basta você importar boot.js em sua página index.html, não importa que posição.

Obrigado Flávio, é meio complexo, vou estudar o código e tentar implementa-lo em TypeScript(estou trocando meus códigos javascript), ficarei ancioso pelo terceiro módulo do curso.

Flavio estudando e implementando o código, em nenhum momento vi onde você associou a função alura-click="importarNegociacoes()" com o controller.

Você tem que escrever o nome do controller na frente. Para fazer igual Angular, você tem que emular shadow dom.

Aliás, isso não é ruim, é excelente fazer isso, porque dá o mesmo efeito do controlerAs do Angular deixando claro onde você esta chamando o método.

Cara, mas o que eu escrevi não tem nada de sofisticado. É javascript puro...

Só isso aqui pode pode confundir:

[...doc.querySelectorAll('[data-controller]')].

Todo NodeList, apesar de ser acessado por índice, não é um array e não podemos fazer forEach. Eu inventei essa estratégia ai misturando spread operator para converter o NodeList em um array para eu poder fazer forEach. For não existe mais, aliás, o Jaffar Russain deu uma palestra com o nome The End of Loop. Eu poderia ter usado um for, mas não rola.

Beleza? Fechou?

Fechou, mas o angular não precisar repetir o nome do controller no click:

Angular:

<button alura-click="funcao()">

O meu tive que fazer:

<button onclick="NomeController.funcao()">

Cara, isso que você esta seguindo cegamente do Angular é uma má prática. Se você tiver 3 controllers aninhados, funcao() é de qual controller? Foi por isso que nas versões mais atuais do Angular você tem controller as.

Contudo, se você quiser repetir o erro das primeiras versões do Angular, terá que emular, como disse, shadow DOM para esconder a chamada do nome do controller.

Beleza, deu certo aqui Flávio, muito obrigado.