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

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 que ele saiba qual é o ponto de input 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

  

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?

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 fazer isso usando o ng-init e uma simples function init.

Aqui está o exemplo disso em plunker

HTML

        

I am {{name}} {{id}}

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) }; }); 

Estou muito atrasado para isso e não tenho idéia se isso é uma boa idéia, mas você pode include o $attrs injetável na function 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, eg, $scope.url = "http://example.com/fetch?model="+$attrs.model; })  

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

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:

         

I am {{name}} {{id}}

Como sugerido por @akonsu e Nigel Findlater, você pode ler o URL em que url é index.html#/user/:id com $routeParams.id e usá-lo dentro do controlador.

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 resources

 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 .

A visão não deve ditar a configuração

Em Angular, o modelo nunca deve ditar a configuração, que é inerentemente o que as pessoas desejam quando desejam passar argumentos para os controladores a partir de um arquivo de modelo. Isso se torna um declive escorregadio. Se as definições de configuração forem codificadas em modelos (por exemplo, por uma diretiva ou atributo de argumento do controlador), você não poderá mais reutilizar esse modelo para nada além desse uso único. Em breve, você vai querer reutilizar esse modelo, mas com uma configuração diferente e, agora, para fazer isso, você estará pré-processando os modelos para injetar variables ​​antes que elas passem para angulares ou usando diretivas massivas para cuspir gigantes blocos de HTML para que você reutilize todo o HTML do controlador, exceto o div do wrapper e seus argumentos. Para pequenos projetos não é grande coisa. Para algo grande (que angular se destaca), fica feio rápido.

A alternativa: módulos

Esse tipo de configuração é o que os módulos foram projetados para manipular. Em muitos tutoriais angulares, as pessoas têm um único módulo para toda a sua aplicação, mas na verdade o sistema é projetado e suporta totalmente muitos módulos pequenos, cada um deles envolvendo pequenas partes do aplicativo total. Idealmente, os controladores, os módulos, etc., seriam declarados em arquivos separados e unidos em partes específicas reutilizáveis. Quando seu aplicativo é projetado dessa maneira, você obtém muita reutilização além dos argumentos fáceis do controlador.

O exemplo abaixo tem 2 módulos, reutilizando o mesmo controlador, mas cada um com suas próprias configurações. Essas configurações são transmitidas através da injeção de dependência usando module.value . Isso se adere ao modo angular porque temos o seguinte: injeção de dependência do construtor, código do controlador reutilizável, modelos de controlador reutilizáveis ​​(o div do controlador pode ser facilmente incluído com ng-include), sistema facilmente testável em unidade sem HTML e por último reutilizável módulos como o veículo para costurar as peças juntas.

Aqui está um exemplo:

  
{{foo}}
{{foo}}

Veja em ação: jsFiddle .

Se o ng-init não é para passar objects para o $scope , você sempre pode escrever sua própria diretiva. Então aqui está o que eu recebi:

http://jsfiddle.net/goliney/89bLj/

Javasript:

 var app = angular.module('myApp', []); app.directive('initData', function($parse) { return function(scope, element, attrs) { //modify scope var model = $parse(attrs.initData); model(scope); }; }); function Ctrl1($scope) { //should be defined $scope.inputdata = {foo:"east", bar:"west"}; } 

Html:

 

Mas minha abordagem só pode modificar objects, que já estão definidos no controlador.

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 isso se você precisar acessar variables ​​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); } }; });  

Use isso se você não precisar acessar as variables ​​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); } }; });  

Eu encontrei variables ​​passantes de $ routeProvider úteis.

Por exemplo, você usa um controlador MyController para várias canvass, passando uma variável muito importante “mySuperConstant” para dentro.

Use essa estrutura simples:

 Router: $routeProvider .when('/this-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "123" }) .when('/that-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "456" }) .when('/another-page', { templateUrl: 'common.html', controller: MyController, mySuperConstant: "789" }) MyController: MyController: function ($scope, $route) { var mySuperConstant: $route.current.mySuperConstant; alert(mySuperConstant); } 

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, enviamos: itemType e a recuperamos depois de $ routeParams.

Existe outra maneira de passar parâmetros para um controlador, injetando $ routeParams em seu controlador e, em seguida, usando os parâmetros de URL descritos aqui. Qual é a maneira mais concisa de ler os parâmetros de consulta no AngularJS?

Essa pergunta é antiga, mas lutei por muito tempo tentando obter uma resposta para esse problema que funcionasse para as minhas necessidades e não o encontrasse facilmente. Acredito que a minha solução a seguir é muito melhor do que a que está sendo aceita atualmente, talvez porque o angular tenha adicionado funcionalidade desde que essa pergunta foi originalmente feita.

Resposta curta, usando o método Module.value permite que você passe dados para um construtor do controlador.

Veja meu plunker aqui

Eu crio um object modelo, depois o associo ao controlador do módulo, referenciando-o com o nome ‘model’

HTML / JS

       
id: {{controller.model.id}}
name: {{controller.model.name}}

O construtor no meu controlador então aceita um parâmetro com o mesmo identificador ‘model’ que ele pode acessar.

Controlador

 function MyController (model) { this.model = model; } MyController.prototype.incrementId = function() { this.model.id = this.model.id + 1; } 

Notas:

Estou usando a boot manual do bootstrapping , que me permite inicializar meu modelo antes de enviá-lo para o angular. Isso funciona muito melhor com o código existente, já que você pode esperar para configurar seus dados relevantes e compilar somente o subconjunto angular do seu aplicativo sob demanda quando quiser.

No plunker, adicionei um botão para alertar os valores do object de modelo que foi inicialmente definido em javascript e passado para angular, apenas para confirmar que o angular está verdadeiramente referenciando o object de modelo, em vez de copiá-lo e trabalhar com uma cópia.

Nesta linha:

 module.controller('MyController', ['model', MyController]); 

Estou passando o object MyController para a function Module.controller, em vez de declarar como uma function inline. Eu acho que isso nos permite definir muito mais claramente o nosso object controlador, mas a documentação Angular tende a fazê-lo em linha, então achei que é preciso esclarecimento.

Estou usando a syntax “controller as” e atribuindo valores à propriedade “this” do MyController, em vez de usar a variável “$ scope”. Eu acredito que isso funcionaria bem usando o $ escopo tão bem, que a atribuição do controlador seria algo como isto:

 module.controller('MyController', ['$scope', 'model', MyController]); 

e o construtor do controlador teria uma assinatura como esta:

 function MyController ($scope, model) { 

Se por qualquer motivo você quisesse, também poderia append esse modelo como um valor de um segundo módulo, que você appendia como uma dependência ao seu módulo primário.

Eu acredito que sua solução é muito melhor do que a atualmente aceita porque

  1. O modelo passado para o controlador é na verdade um object javascript, não uma string que é avaliada. É uma referência verdadeira ao object e as alterações afetam outras referências a esse object de modelo.
  2. Angular diz que o uso do ng-init pela resposta aceita é um mau uso, o que esta solução não faz.

O modo como o Angular parece funcionar na maioria dos outros exemplos que eu vi tem o controlador definindo os dados do modelo, o que nunca fez sentido para mim, não há separação entre o modelo e o controlador, que realmente não parece MVC para mim. Essa solução permite que você realmente tenha um object de modelo completamente separado que você passa para o controlador. Além disso, se você usar a diretiva ng-include, poderá colocar todo o seu arquivo HTML angular em um arquivo separado, separando totalmente a visualização do modelo e o controlador em partes modulares separadas.

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 dependencies para “resolver” antes que o controlador seja instanciado. Você pode declarar dependencies para cada um dos seus “estados”. Essas dependencies são então passadas no “construtor” do controlador.

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.

Não, não é possível. Eu acho que você pode usar o ng-init como hackear http://docs.angularjs.org/api/ng.directive:ngInit .

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

 

Nesta soluçã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!)