directives - javascript angular module



Você pode passar parâmetros para um controlador AngularJS na criação? (11)

Eu tenho um controlador responsável por se comunicar com uma API para atualizar as propriedades de um usuário, nome, email, etc. Cada usuário tem um 'id' que é passado do servidor quando a página de perfil é visualizada.

Eu gostaria de passar esse valor para o controlador AngularJS para saber qual é o ponto de entrada da API para o usuário atual. Eu tentei passar o valor no ng-controller . Por exemplo:

function UserCtrl(id, $scope, $filter) {

$scope.connection = $resource('api.com/user/' + id)

e no HTML

<body ng-controller="UserCtrl({% id %})">

onde {% id %} imprime o id enviado do servidor. mas eu recebo erros.

Qual é a maneira correta de passar um valor para um controlador em sua criação?


Answer #1

Aqui está uma solução (baseada na sugestão de Marcin Wyszynski) que funciona onde você quer passar um valor para seu controller mas você não está explicitamente declarando o controller em seu html (que ng-init parece requerer) - se, por exemplo, você está renderizando seus templates com ng-view e declarando cada controller para a rota correspondente via routeProvider.

JS

messageboard.directive('currentuser', ['CurrentUser', function(CurrentUser) {
  return function(scope, element, attrs) {
    CurrentUser.name = attrs.name;
  };
}]);

html

<div ng-app="app">
  <div class="view-container">
    <div ng-view currentuser name="testusername" class="view-frame animate-view"></div>
  </div>
</div>

Nesta solução, o CurrentUser é um serviço que pode ser injetado em qualquer controlador, com a propriedade .name disponível.

Duas notas:

  • Um problema que eu encontrei é que. Nome é definido após o controlador carrega, assim como uma solução alternativa eu ​​tenho um tempo limite curto antes de renderizar o nome de usuário no escopo do controlador. Existe uma maneira legal de esperar até que o nome seja definido no serviço?

  • Isso parece uma maneira muito fácil de obter um usuário atual em seu aplicativo Angular com toda a autenticação mantida fora do Angular. Você poderia ter um before_filter para evitar que usuários não logados acessassem o html onde seu aplicativo Angular é inicializado, e dentro desse html você poderia simplesmente interpolar o nome do usuário logado e até mesmo seu ID se você quisesse interagir com os detalhes do usuário via solicitações de http do seu aplicativo Angular. Você pode permitir que usuários não conectados usem o aplicativo Angular com um 'usuário convidado' padrão. Qualquer conselho sobre por que essa abordagem seria ruim seria bem-vindo - parece fácil demais ser sensato!)


Answer #2

Como @akonsu e Nigel Findlater sugerem, você pode ler o url onde url é index.html#/user/:id com $routeParams.id e usá-lo dentro do controller.

seu aplicativo:

var app = angular.module('myApp', [ 'ngResource' ]);

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/:type/:id', {templateUrl: 'myView.html', controller: 'myCtrl'});
}]);

o serviço de recursos

app.factory('MyElements', ['$resource', function($resource) {
     return $resource('url/to/json/:type/:id', { type:'@type', id:'@id' });
}]);

o controlador

app.controller('MyCtrl', ['$scope', '$routeParams', 'MyElements', function($scope, $routeParams, MyElements) {
    MyElements.get({'type': $routeParams.type, "id": $routeParams.id }, function(elm) {
        $scope.elm = elm;
    })
}]);

então, elm é acessível na visão dependendo do id .


Answer #3

Esta é uma expansão da excelente resposta de @Michael Tiller. Sua resposta funciona para inicializar variáveis ​​da visão, injetando o objeto $attrs no controlador. O problema ocorre se o mesmo controlador é chamado de $routeProvider quando você navega pelo roteamento. Então você obtém o erro de injector Unknown provider : $attrsProvider porque $attrs está disponível apenas para injeção quando a visualização é compilada. A solução é passar a variável (foo) por meio de $routeParams ao inicializar o controlador da rota e por $attrs ao inicializar o controlador da visualização. Aqui está minha solução.

Da rota

$routeProvider.
        when('/mypage/:foo', {
            templateUrl: 'templates/mypage.html',
            controller: 'MyPageController',
            caseInsensitiveMatch: true,
            resolve: {
                $attrs: function () {
                    return {};
                }
            }
        });

Isso lida com um URL como '/mypage/bar' . Como você pode ver, foo é passado por url param e nós fornecemos o $injector com um objeto em branco para $attrs então nenhum erro de injetor.

Da vista

<div ng-controller="MyPageController" data-foo="bar">

</div>

Agora o controlador

var app = angular.module('myapp', []);
app.controller('MyPageController',['$scope', '$attrs', '$routeParams'], function($scope, $attrs, $routeParams) {
   //now you can initialize foo. If $attrs contains foo, it's been initialized from view
   //else find it from $routeParams
   var foo = $attrs.foo? $attrs.foo : $routeParams.foo;
   console.log(foo); //prints 'bar'

});

Answer #4

Estou muito atrasado para isso e não tenho idéia se isso é uma boa idéia, mas você pode incluir o $attrs injetável na função do controlador permitindo que o controlador seja inicializado usando "argumentos" fornecidos em um elemento, por exemplo

app.controller('modelController', function($scope, $attrs) {
    if (!$attrs.model) throw new Error("No model for modelController");

    // Initialize $scope using the value of the model attribute, e.g.,
    $scope.url = "http://example.com/fetch?model="+$attrs.model;
})

<div ng-controller="modelController" model="foobar">
  <a href="{{url}}">Click here</a>
</div>

Mais uma vez, não faço ideia se é uma boa ideia, mas parece funcionar e é outra alternativa.



Answer #6

Isso também funciona.

Javascript:

var app = angular.module('angularApp', []);

app.controller('MainCtrl', function($scope, name, id) {
    $scope.id = id;
    $scope.name = name;
    // and more init
});

Html:

<!DOCTYPE html>
<html ng-app="angularApp">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
    <script>
       app.value("name", "James").value("id", "007");
    </script>
  </head>
  <body ng-controller="MainCtrl">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

Answer #7

Parece que a melhor solução para você é na verdade uma diretiva. Isso permite que você ainda tenha seu controlador, mas defina propriedades personalizadas para ele.

Use isto se você precisar acessar variáveis ​​no escopo de quebra automática:

angular.module('myModule').directive('user', function ($filter) {
  return {
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + attrs.userId);
    }
  };
});

<user user-id="{% id %}"></user>

Use isso se você não precisar acessar as variáveis ​​no escopo de quebra automática:

angular.module('myModule').directive('user', function ($filter) {
  return {
    scope: {
      userId: '@'
    },
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + scope.userId);
    }
  };
});

<user user-id="{% id %}"></user>

Answer #8

Se estiver usando o roteador angular-ui, essa é a solução correta: https://github.com/angular-ui/ui-router/wiki#resolve

Basicamente, você declara um conjunto de dependências para "resolver" antes que o controlador seja instanciado. Você pode declarar dependências para cada um dos seus "estados". Essas dependências são então passadas no "construtor" do controlador.


Answer #9

Uma maneira de fazer isso seria ter um serviço separado que possa ser usado como um 'recipiente' para os argumentos em que eles são membros de dados públicos.


Answer #10

Você pode fazê-lo ao configurar as rotas para, por exemplo,

 .when('/newitem/:itemType', {
            templateUrl: 'scripts/components/items/newEditItem.html',
            controller: 'NewEditItemController as vm',
            resolve: {
              isEditMode: function () {
                return true;
              }
            },
        })

E depois usá-lo como

(function () {
  'use strict';

  angular
    .module('myApp')
    .controller('NewEditItemController', NewEditItemController);

  NewEditItemController.$inject = ['$http','isEditMode',$routeParams,];

  function NewEditItemController($http, isEditMode, $routeParams) {
    /* jshint validthis:true */

    var vm = this;
    vm.isEditMode = isEditMode;
    vm.itemType = $routeParams.itemType;
  }
})();

Então, aqui, quando configuramos a rota que enviamos: itemType e a recuperamos depois de $ routeParams.


Answer #11

Notas:

Essa resposta é antiga. Esta é apenas uma prova de conceito sobre como o resultado desejado pode ser alcançado. No entanto, pode não ser a melhor solução, conforme alguns comentários abaixo. Eu não tenho nenhuma documentação para apoiar ou rejeitar a seguinte abordagem. Por favor, consulte alguns dos comentários abaixo para uma discussão mais aprofundada sobre este tópico.

Resposta Original:

Eu respondi isso para sim você absolutamente pode fazê-lo usando ng-init e uma função de inicialização simples.

Aqui está o exemplo disso em plunker

HTML

<!DOCTYPE html>
<html ng-app="angularjs-starter">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
  </head>  
  <body ng-controller="MainCtrl" ng-init="init('James Bond','007')">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

JavaScript

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope) {

  $scope.init = function(name, id)
  {
    //This function is sort of private constructor for controller
    $scope.id = id;
    $scope.name = name; 
    //Based on passed argument you can make a call to resource
    //and initialize more objects
    //$resource.getMeBond(007)
  };


});




angularjs