javascript - parametros - ¿Se pueden pasar parámetros a un controlador AngularJS en la creación?
pasar parametros entre controladores angular 2 (15)
Al igual que @akonsu y Nigel Findlater sugieren, puede leer la url donde url es index.html#/user/:id
con $routeParams.id
y usarla dentro del controlador.
su aplicación:
var app = angular.module(''myApp'', [ ''ngResource'' ]);
app.config([''$routeProvider'', function($routeProvider) {
$routeProvider.when(''/:type/:id'', {templateUrl: ''myView.html'', controller: ''myCtrl''});
}]);
el servicio de recursos
app.factory(''MyElements'', [''$resource'', function($resource) {
return $resource(''url/to/json/:type/:id'', { type:''@type'', id:''@id'' });
}]);
el controlador
app.controller(''MyCtrl'', [''$scope'', ''$routeParams'', ''MyElements'', function($scope, $routeParams, MyElements) {
MyElements.get({''type'': $routeParams.type, "id": $routeParams.id }, function(elm) {
$scope.elm = elm;
})
}]);
entonces, elm
es accesible en la vista dependiendo de la id
.
Tengo un controlador responsable de la comunicación con una API para actualizar las propiedades de un usuario, nombre, correo electrónico, etc. Cada usuario tiene un ''id''
que se pasa desde el servidor cuando se visualiza la página de perfil.
Me gustaría pasar este valor al controlador AngularJS para que sepa cuál es el punto de entrada de la API para el usuario actual. He intentado pasar el valor en ng-controller
. Por ejemplo:
function UserCtrl(id, $scope, $filter) {
$scope.connection = $resource(''api.com/user/'' + id)
y en el HTML
<body ng-controller="UserCtrl({% id %})">
donde {% id %}
imprime la identificación enviada desde el servidor. pero me sale errores.
¿Cuál es la forma correcta de pasar un valor a un controlador en su creación?
Aquí hay una solución (basada en la sugerencia de Marcin Wyszynski) que funciona donde usted quiere pasar un valor a su controlador pero no está declarando explícitamente el controlador en su html (que ng-init parece requerir) - si, por ejemplo, está procesando sus plantillas con ng-view y declarando a cada controlador la ruta correspondiente a través de 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>
En esta solución, CurrentUser es un servicio que se puede inyectar en cualquier controlador, con la propiedad .name disponible.
Dos notas:
un problema que he encontrado es que .name se establece después de que se carga el controlador, por lo que como solución temporal tengo un breve tiempo de espera antes de representar el nombre de usuario en el alcance del controlador. ¿Hay alguna forma de esperar hasta que se haya configurado .name en el servicio?
Esto se siente como una manera muy fácil de obtener un usuario actual en su aplicación Angular con toda la autenticación fuera de Angular. Podría tener un before_filter para evitar que los usuarios que no han iniciado sesión accedan al html donde se reinicie su aplicación Angular, y dentro de ese html podría interpolar el nombre del usuario registrado e incluso su ID si quisiera interactuar con los detalles del usuario a través de las solicitudes http de su aplicación Angular. Puede permitir que los usuarios que no han iniciado sesión utilicen la aplicación Angular con un "usuario invitado" predeterminado. Cualquier consejo sobre por qué este enfoque sería malo sería bienvenido, ¡parece demasiado fácil ser sensato!
Encontré variables de paso de $ routeProvider útiles.
Por ejemplo, utiliza un controlador MyController para varias pantallas, pasando una variable muy importante "mySuperConstant" dentro.
Usa esa estructura simple:
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);
}
Esta pregunta es antigua pero luché durante mucho tiempo tratando de obtener una respuesta a este problema que funcionara para mis necesidades y no la encontré fácilmente. Creo que mi siguiente solución es mucho mejor que la aceptada actualmente, tal vez porque angular ha agregado funcionalidad desde que se planteó esta pregunta originalmente.
Respuesta corta, usando el método Module.value le permite pasar datos a un constructor de controlador.
Ver mi plunker here
Creo un objeto modelo, luego lo asocio con el controlador del módulo, haciendo referencia a él con el nombre ''modelo''
HTML / JS
<html>
<head>
<script>
var model = {"id": 1, "name":"foo"};
$(document).ready(function(){
var module = angular.module(''myApp'', []);
module.value(''model'', model);
module.controller(''MyController'', [''model'', MyController]);
angular.bootstrap(document, [''myApp'']);
});
function confirmModelEdited() {
alert("model name: " + model.name + "/nmodel id: " + model.id);
}
</script>
</head>
<body >
<div ng-controller="MyController as controller">
id: {{controller.model.id}} <br>
name: <input ng-model="controller.model.name"/>{{controller.model.name}}
<br><button ng-click="controller.incrementId()">increment ID</button>
<br><button onclick="confirmModelEdited()">confirm model was edited</button>
</div>
</body>
</html>
El constructor en mi controlador luego acepta un parámetro con el mismo identificador ''modelo'' al cual puede acceder.
Controlador
function MyController (model) {
this.model = model;
}
MyController.prototype.incrementId = function() {
this.model.id = this.model.id + 1;
}
Notas:
Estoy usando la inicialización manual de bootstrapping , lo que me permite inicializar mi modelo antes de enviarlo a angular. Esto se reproduce mucho mejor con el código existente, ya que puede esperar para configurar sus datos relevantes y solo compilar el subconjunto angular de su aplicación cuando lo desee.
En el plunker, agregué un botón para alertar los valores del objeto modelo que se definió inicialmente en javascript y se pasó a angular, solo para confirmar que angular realmente está haciendo referencia al objeto modelo, en lugar de copiarlo y trabajar con una copia.
En esta línea:
module.controller(''MyController'', [''model'', MyController]);
Estoy pasando el objeto MyController a la función Module.controller, en lugar de declararlo como una función en línea. Creo que esto nos permite definir mucho más claramente nuestro objeto controlador, pero la documentación angular tiende a hacerlo en línea, por lo que pensé que es una aclaración.
Estoy usando la sintaxis "controller as" y asignando valores a la propiedad "this" de MyController, en lugar de usar la variable "$ scope". Creo que esto funcionaría bien usando $ scope de la misma manera, la asignación del controlador se vería así:
module.controller(''MyController'', [''$scope'', ''model'', MyController]);
y el constructor del controlador tendría una firma como esta:
function MyController ($scope, model) {
Si por cualquier motivo lo deseara, también podría adjuntar este modelo como un valor de un segundo módulo, que luego adjuntará como una dependencia a su módulo primario.
Creo que su solución es mucho mejor que la actualmente aceptada porque
- El modelo pasado al controlador es en realidad un objeto javascript, no una cadena que se evalúa. Es una verdadera referencia al objeto y los cambios en él afectan a otras referencias a este objeto modelo.
- Angular dice que el uso aceptado de ng-init por la respuesta aceptada es un uso incorrecto, lo que no hace esta solución.
La forma en que Angular parece funcionar en la mayoría de los otros ejemplos que he visto tiene al controlador que define los datos del modelo, lo que nunca tuvo sentido para mí, no hay una separación entre el modelo y el controlador, que realmente no parece ser MVC para mí. Esta solución le permite tener un objeto de modelo completamente separado que pasa al controlador. También debe tener en cuenta que si usa la directiva ng-include, puede colocar todos sus html angulares en un archivo separado, separando completamente la vista del modelo y el controlador en piezas modulares separadas.
Esto también 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>
Hay otra manera de pasar parámetros a un controlador inyectando $ routeParams en su controlador y luego utilizando los parámetros de URL descritos aquí. ¿Cuál es la forma más concisa de leer los parámetros de consulta en AngularJS?
Llego muy tarde a esto y no tengo idea de si es una buena idea, pero puede incluir el $attrs
inyectable en la función del controlador que permite que el controlador se inicialice usando "argumentos" proporcionados en un elemento, por ejemplo
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>
Nuevamente, no tengo idea si es una buena idea, pero parece funcionar y es otra alternativa.
No, no es posible. Creo que puedes usar ng-init como hack http://docs.angularjs.org/api/ng.directive:ngInit .
Parece que la mejor solución para ti es en realidad una directiva. Esto le permite tener su controlador, pero definir propiedades personalizadas para él.
Use esto si necesita acceder a las variables en el ámbito de ajuste:
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 esto si no necesita acceder a las variables en el ámbito de ajuste:
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>
Puedes hacerlo al configurar las rutas para, por ejemplo,
.when(''/newitem/:itemType'', {
templateUrl: ''scripts/components/items/newEditItem.html'',
controller: ''NewEditItemController as vm'',
resolve: {
isEditMode: function () {
return true;
}
},
})
Y luego usarlo 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;
}
})();
Así que aquí cuando configuramos la ruta que enviamos: itemType y la recuperamos más tarde desde $ routeParams.
Si ng-init
no es para pasar objetos a $scope
, siempre puede escribir su propia directiva. Así que aquí está lo que tengo:
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:
<div ng-controller="Ctrl1">
<div init-data="inputdata.foo=123; inputdata.bar=321"></div>
</div>
Pero mi enfoque solo puede modificar objetos, que ya están definidos en el controlador.
Si usa un enrutador ui angular, esta es la solución correcta: https://github.com/angular-ui/ui-router/wiki#resolve
Básicamente, usted declara que un conjunto de dependencias se "resuelve" antes de que se cree una instancia del controlador. Puede declarar dependencias para cada uno de sus "estados". Estas dependencias se pasan luego en el "constructor" del controlador.
Una forma de hacerlo sería tener un servicio separado que se pueda usar como un "buque" para aquellos argumentos en los que son miembros de datos públicos.
La vista no debe dictar la configuración.
En Angular, la plantilla nunca debe dictar la configuración, que es inherentemente lo que las personas desean cuando desean pasar argumentos a los controladores desde un archivo de plantilla. Esto se convierte en una pendiente resbaladiza. Si las configuraciones de configuración están codificadas de forma rígida en las plantillas (por ejemplo, por una directiva o un atributo de argumento del controlador), ya no puede reutilizar esa plantilla para nada más que ese uso único. Pronto querrá reutilizar esa plantilla, pero con una configuración diferente, y ahora para hacerlo, deberá preprocesar las plantillas para inyectar variables antes de que pasen a angular o usar directivas masivas para escupir gigantes bloques de HTML para que reutilices todo el controlador HTML, excepto el envoltorio div y sus argumentos. Para pequeños proyectos no es gran cosa. Para algo grande (en lo que sobresale el ángulo), se pone muy rápido.
La Alternativa: Módulos
Este tipo de configuración es lo que los módulos fueron diseñados para manejar. En muchos tutoriales angulares, las personas tienen un solo módulo para toda su aplicación, pero en realidad el sistema está diseñado y es totalmente compatible con muchos módulos pequeños, cada uno de los cuales envuelve partes pequeñas de la aplicación total. Lo ideal sería que los controladores, módulos, etc. se declararan en archivos separados y se unieran en fragmentos específicos reutilizables. Cuando su aplicación está diseñada de esta manera, obtiene una gran cantidad de reutilización además de argumentos de controlador fáciles.
El ejemplo a continuación tiene 2 módulos, reutilizando el mismo controlador, pero cada uno con sus propios ajustes de configuración. Esa configuración se pasa a través de la inyección de dependencias usando module.value
. Esto se adhiere a la vía angular porque tenemos lo siguiente: inyección de dependencia del constructor, código de controlador reutilizable, plantillas de controlador reutilizables (el div controlador podría incluirse fácilmente con ng-include), sistema fácilmente verificable por unidad sin HTML y, por último, reutilizable Módulos como el vehículo para unir las piezas.
Aquí hay un ejemplo:
<!-- index.html -->
<div id="module1">
<div ng-controller="MyCtrl">
<div>{{foo}}</div>
</div>
</div>
<div id="module2">
<div ng-controller="MyCtrl">
<div>{{foo}}</div>
</div>
</div>
<script>
// part of this template, or a JS file designed to be used with this template
angular.element(document).ready(function() {
angular.bootstrap(document.getElementById("module1"), ["module1"]);
angular.bootstrap(document.getElementById("module2"), ["module2"]);
});
</script>
<!-- scripts which will likely in be in their seperate files -->
<script>
// MyCtrl.js
var MyCtrl = function($scope, foo) {
$scope.foo = foo;
}
MyCtrl.$inject = ["$scope", "foo"];
// Module1.js
var module1 = angular.module(''module1'', []);
module1.value("foo", "fooValue1");
module1.controller("MyCtrl", MyCtrl);
// Module2.js file
var module2 = angular.module(''module2'', []);
module2.value("foo", "fooValue2");
module2.controller("MyCtrl", MyCtrl);
</script>
Notas:
Esta respuesta es antigua. Esto es solo una prueba de concepto sobre cómo se puede lograr el resultado deseado. Sin embargo, puede que no sea la mejor solución según algunos comentarios a continuación. No tengo ninguna documentación para apoyar o rechazar el siguiente enfoque. Consulte algunos de los comentarios a continuación para obtener más información sobre este tema.
Respuesta original:
Respondí esto a Sí. Absolutamente puedes hacerlo usando ng-init
y una simple función init.
Aquí está el ejemplo de ello en 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)
};
});