Puoi passare i parametri a un controller AngularJS al momento della creazione?


278

Ho un controller responsabile della comunicazione con un'API per aggiornare le proprietà di un utente, nome, e-mail, ecc. Ogni utente ha un 'id'che viene passato dal server quando viene visualizzata la pagina del profilo.

Vorrei passare questo valore al controller AngularJS in modo che sappia quale sia il punto di ingresso API per l'utente corrente. Ho provato a passare il valore ng-controller. Per esempio:

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

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

e nel codice HTML

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

dove {% id %}stampare l'id inviato dal server. ma ricevo errori.

Qual è il modo corretto di passare un valore a un controller al momento della sua creazione?


6
se avessi l'ID come parte
dell'URL,

Ho avuto un problema molto simile e l'ho risolto come ho scritto nella mia risposta. A volte usando le librerie trascuriamo un semplice concetto fondamentale di chiamata di funzione JavaScript.
Jigar Patel,

@nickponline Dopo 21+ pensi ancora che non sia possibile?
om471987,

Risposte:


362

Appunti:

Questa risposta è vecchia. Questa è solo una prova del concetto di come si possa ottenere il risultato desiderato. Tuttavia, potrebbe non essere la soluzione migliore secondo alcuni commenti qui sotto. Non ho documentazione per supportare o rifiutare il seguente approccio. Fare riferimento ad alcuni dei commenti seguenti per ulteriori discussioni su questo argomento.

Risposta originale:

Ho risposto a Sì, puoi assolutamente farlo usando ng-inite una semplice funzione init.

Ecco l'esempio su 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)
  };


});

5
Grazie per questo - mi ha risparmiato un sacco di grattacapi e ha funzionato perfettamente per la mia situazione. Ho dovuto inizializzare il mio controller con un ID oggetto, e questo era giusto.
Masonoise,

26
Da documenti :The only appropriate use of ngInit for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Sergey Goliney,

8
La risposta chiarisce che il documento raccomanda di non adottare questo approccio, ma qualcuno può indicarmi dove i documenti forniscono la soluzione ufficiale?
Michael Pell,

53
Beh, penso che i documenti siano scarsi nel raccomandare solo questo approccio senza dare ragioni. Penso che questo sia un approccio geniale. Se gli autori del framework non vogliono che il framework venga utilizzato in un modo "sbagliato" per loro, allora non dovrebbero consentire di usarlo in quel modo "sbagliato" ... e fornire una guida riguardo al " giusta direzione!
Shawn de Wet,

2
un avvertimento: se si sta tentando di associarsi a un valore di ambito o si fa davvero qualcosa che si aspetta che il valore sia presente nella funzione controller, è già in esecuzione la funzione controller prima che si ng-initverifichi, vedere plnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = preview
drzaus,

143

Sono in ritardo e non ho idea se sia una buona idea, ma puoi includere l' $attrsiniettore nella funzione controller che consente di inizializzare il controller usando "argomenti" forniti su un elemento, ad es.

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>

Ancora una volta, non ho idea se questa è una buona idea, ma sembra funzionare ed è un'altra alternativa.


3
Come passerei un oggetto usando questo approccio? var obj = {a: 1, b: 2};
Neil,

3
Questa è una soluzione molto ragionevole al problema di produrre un'app ibrida.
superluminario,

2
@Neil: devi stringere il tuo oggetto json e poi analizzarlo all'interno del controller. Non è la soluzione migliore, ma potrebbe funzionare. La soluzione di Michael va bene per parametri simili a stringhe ...
M'sieur Toph '

1
questo è in realtà più affidabile dell'uso ng-init- se stai cercando di associare un valore di ambito, è già in esecuzione la funzione controller prima che si ng-initverifichi - vedi plnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview
drzaus

2
Non riesco a reinventare la ruota con direttive ecc. Se si dispone di un controller che si desidera utilizzare in più viste con alcuni parametri di inizializzazione diversi, questa è la soluzione più semplice e affidabile.
Eric H.

39

Questo funziona anche.

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>

3
Questa è una buona soluzione che funziona con il meccanismo di iniezione del costruttore esistente. In sostanza, stai creando due semplici servizi chiamati "nome" e "id". L'iniettore si occupa di abbinarli per nome durante la costruzione. Vedi: la sezione Ricetta del valore
Todd

1
Bello. Nota che funziona anche con oggetti, non solo tipi primitivi come le stringhe.
jbustamovej,

Mi piace di più questa soluzione. Sono stato in grado di modulare i miei codici duplicati tramite il passaggio dei parametri. Saluti!
agentpx,

Sembra il modo più idiomatico, ma non sono sicuro che sia raccomandato dalla squadra angolare
VinGarcia,

Questo essenzialmente imposta coppie chiave / valore globali? Questi possono essere indirizzati a una determinata istanza del controller in modo che venga raccolto solo su controller figlio sotto quello principale? Altrimenti sembra che questo non sia molto diverso dall'impostare una normale variabile Javascript globale a livello di finestra.
jpierson,

16

La vista non dovrebbe dettare la configurazione

In Angular, il modello non dovrebbe mai dettare la configurazione, che è intrinsecamente ciò che le persone desiderano quando vogliono passare argomenti ai controller da un file modello. Questo diventa un pendio scivoloso. Se le impostazioni di configurazione sono codificate nei modelli (ad esempio da una direttiva o da un attributo dell'argomento controller), non è più possibile riutilizzare quel modello per scopi diversi da quello monouso. Presto vorrai riutilizzare quel modello, ma con una diversa configurazione e ora per farlo dovrai pre-elaborare i modelli per iniettare le variabili prima che venga passato ad angolare o usare direttive di massa per sputare gigante blocchi di HTML in modo da riutilizzare tutto l'HTML del controller ad eccezione del div wrapper e dei suoi argomenti. Per i piccoli progetti non è un grosso problema. Per qualcosa di grande (ciò che eccelle in angolare), diventa brutto in fretta.

L'alternativa: moduli

Questo tipo di configurazione è ciò che i moduli sono stati progettati per gestire. In molti tutorial angolari le persone hanno un singolo modulo per la loro intera applicazione, ma in realtà il sistema è progettato e supporta completamente molti piccoli moduli ognuno che avvolge piccoli pezzi dell'applicazione totale. Idealmente, controller, moduli ecc. Sarebbero dichiarati in file separati e cuciti insieme in specifici blocchi riutilizzabili. Quando la tua applicazione è progettata in questo modo, ottieni molto riutilizzo oltre agli argomenti del controller.

L'esempio seguente ha 2 moduli, riutilizzando lo stesso controller, ma ognuno con le proprie impostazioni di configurazione. Le impostazioni di configurazione vengono passate tramite l'iniezione delle dipendenze tramite module.value. Questo aderisce al modo angolare perché abbiamo i seguenti: iniezione di dipendenza del costruttore, codice controller riutilizzabile, modelli di controller riutilizzabili (il div controller potrebbe essere facilmente incluso in ng-include), sistema facilmente testabile dall'unità senza HTML e infine riutilizzabile moduli come veicolo per ricucire i pezzi.

Ecco un esempio:

<!-- 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>

Guardalo in azione: jsFiddle .


ho già votato, ma voglio esprimere i miei ringraziamenti per il tuo contributo. questa risposta mi ha messo su una strada migliore. stackoverflow è il migliore quando le persone condividono le migliori pratiche e non solo frammenti di schifezze. questo è geniale: "il modello non dovrebbe mai dettare la configurazione, che è intrinsecamente ciò che le persone desiderano quando vogliono passare argomenti ai controller da un file modello". grazie per avere la visione laser nel cuore della questione.
pestofago

15

Come @akonsu e Nigel Findlater suggeriscono, si può leggere l'URL in cui URL è index.html#/user/:idcon $routeParams.ide utilizzarlo all'interno del controllore.

la tua app:

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

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

il servizio di risorse

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

il controller

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

quindi, elmè accessibile nella vista a seconda di id.


8

Se ng-initnon è per passare oggetti in $scope, puoi sempre scrivere la tua direttiva. Quindi ecco quello che ho ottenuto:

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>

Ma il mio approccio può solo modificare oggetti, che sono già definiti sul controller.


Per riferimento funziona alla grande ma sulla versione attuale di angular è $ attrs (vs attrs)
Dinis Cruz

8

Sembra che la soluzione migliore per te sia in realtà una direttiva. Ciò consente di avere ancora il controller, ma definire proprietà personalizzate per esso.

Usalo se hai bisogno di accedere alle variabili nell'ambito del wrapping:

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>

Usalo se non hai bisogno di accedere alle variabili nell'ambito del wrapping:

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>

7

Ho trovato utili le variabili di passaggio da $ routeProvider.

Ad esempio, si utilizza un controller MyController per più schermate, passando all'interno di una variabile molto importante "mySuperConstant".

Usa quella semplice struttura:

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

    }

6

Puoi farlo durante l'impostazione dei percorsi per es

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

E in seguito usarlo come

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

Quindi qui quando impostiamo il percorso che abbiamo inviato: itemType e riavvialo successivamente da $ routeParams.



3

Questa domanda è vecchia ma ho lottato a lungo cercando di ottenere una risposta a questo problema che avrebbe funzionato per le mie esigenze e non lo trovasse facilmente. Credo che la mia seguente soluzione sia molto migliore di quella attualmente accettata, forse perché angolare ha aggiunto funzionalità da quando questa domanda è stata posta inizialmente.

Risposta breve, l'utilizzo del metodo Module.value consente di passare i dati a un costruttore di controller.

Vedi il mio plunker qui

Creo un oggetto modello, quindi lo associo al controller del modulo, facendo riferimento a esso con il nome "modello"

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>

Il costruttore nel mio controller accetta quindi un parametro con lo stesso identificatore "modello" a cui può accedere.

controllore

function MyController (model) {
  this.model = model;
}

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

Appunti:

Sto usando l'inizializzazione manuale del bootstrap , che mi consente di inizializzare il mio modello prima di inviarlo ad angolare. Questo si gioca molto più bene con il codice esistente, poiché puoi aspettare di impostare i dati pertinenti e compilare il sottoinsieme angolare dell'app su richiesta quando vuoi.

Nel plunker ho aggiunto un pulsante per avvisare i valori dell'oggetto modello inizialmente definiti in javascript e passati ad angolare, solo per confermare che angolare fa veramente riferimento all'oggetto modello, piuttosto che copiarlo e lavorare con una copia.

Su questa linea:

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

Sto passando l'oggetto MyController nella funzione Module.controller, piuttosto che dichiarare come una funzione in linea. Penso che questo ci consenta di definire in modo molto più chiaro il nostro oggetto controller, ma la documentazione angolare tende a farlo in linea, quindi ho pensato che portasse chiarimenti.

Sto usando la sintassi "controller as" e assegnando i valori alla proprietà "this" di MyController, anziché utilizzare la variabile "$ scope". Credo che funzionerebbe bene usando $ scope allo stesso modo, l'assegnazione del controller sarebbe quindi simile a questa:

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

e il costruttore del controller avrebbe una firma come questa:

function MyController ($scope, model) {

Se, per qualsiasi motivo, volessi, puoi anche collegare questo modello come valore di un secondo modulo, che poi aggiungi come dipendenza al tuo modulo principale.

Credo che la sua soluzione sia molto migliore di quella attualmente accettata perché

  1. Il modello passato al controller è in realtà un oggetto javascript, non una stringa che viene valutata. È un vero riferimento all'oggetto e le modifiche ad esso influiscono su altri riferimenti a questo oggetto modello.
  2. Angular afferma che l'uso della risposta accettata di ng-init è un uso improprio, cosa che questa soluzione non ha.

Il modo in cui Angular sembra funzionare nella maggior parte degli altri esempi che ho visto ha il controller che definisce i dati del modello, il che non ha mai avuto senso per me, non c'è separazione tra il modello e il controller, che in realtà non sembra MVC per me. Questa soluzione ti consente di avere davvero un oggetto modello completamente separato che passi nel controller. Inoltre, se usi la direttiva ng-include puoi mettere tutto il tuo html angolare in un file separato, separando completamente la vista del modello e il controller in pezzi modulari separati.


2

Se si utilizza angular-ui-router, questa è la soluzione corretta: https://github.com/angular-ui/ui-router/wiki#resolve

Fondamentalmente, si dichiara una serie di dipendenze da "risolvere" prima di istanziare il controller. Puoi dichiarare dipendenze per ciascuno dei tuoi "stati". Queste dipendenze vengono quindi passate nel "costruttore" del controller.


1

Un modo per farlo sarebbe avere un servizio separato che può essere usato come "nave" per quegli argomenti in cui sono membri di dati pubblici.


Migliore risposta, IMO. Attualmente uso anche l'archiviazione del browser in alcuni casi per quegli utenti che hanno il coraggio di premere F5, quindi questo stato viene mantenuto.
Ghiro

1

Non mi è piaciuta molto nessuna delle soluzioni qui per il mio caso d'uso particolare, quindi ho pensato di pubblicare quello che ho fatto perché non l'ho visto qui.

Volevo semplicemente usare un controller più simile a una direttiva, all'interno di un ciclo ng-repeat:

<div ng-repeat="objParameter in [{id:'a'},{id:'b'},{id:'c'}]">
  <div ng-controller="DirectiveLikeController as ctrl"></div>
</div>

Ora, per accedere alla objParametercreazione al momento all'interno di ogni DirettivaLikeController (o per ottenere l'objParameter aggiornato in QUALSIASI momento), tutto ciò che devo fare è iniettare $ scope e chiamare $scope.$eval('objParameter'):

var app = angular.module('myapp', []);
app.controller('DirectiveLikeController',['$scope'], function($scope) {
   //print 'a' for the 1st instance, 'b' for the 2nd instance, and 'c' for the 3rd.
   console.log($scope.$eval('objParameter').id); 
});

L'unico vero inconveniente che vedo è che richiede al controller principale di sapere che il parametro è denominato objParameter.


0

No, non è possibile. Penso che tu possa usare ng-init come hack http://docs.angularjs.org/api/ng.directive:ngInit .


4
Mi permetto di dissentire, ma puoi farlo usando ng-init e usando un init fuction.
Jigar Patel,

un avvertimento: se si sta tentando di associarsi a un valore di ambito o si fa davvero qualcosa che si aspetta che il valore sia presente nella funzione controller, è già in esecuzione la funzione controller prima che si ng-initverifichi, vedere plnkr.co/edit / donCm6FRBSX9oENXh9WJ? p = preview
drzaus,

Sì, è possibile. Come minimo, useresti parametri di dati o altro. Ma è sicuramente possibile.
Juan,

0

Ecco una soluzione (basata sul suggerimento di Marcin Wyszynski) che funziona dove vuoi passare un valore nel tuo controller ma non stai dichiarando esplicitamente il controller nel tuo html (cosa che ng-init sembra richiedere) - se, ad esempio, stai eseguendo il rendering dei tuoi modelli con ng-view e stai dichiarando ogni controller per il percorso corrispondente tramite 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>

In questa soluzione, CurrentUser è un servizio che può essere iniettato in qualsiasi controller, con la proprietà .name quindi disponibile.

Due note:

  • un problema che ho riscontrato è che .name viene impostato dopo il caricamento del controller, quindi come soluzione alternativa ho un breve timeout prima di eseguire il rendering del nome utente nell'ambito del controller. C'è un modo preciso di aspettare fino a quando .name è stato impostato sul servizio?

  • questo sembra un modo molto semplice per ottenere un utente corrente nella tua App Angular con tutta l'autenticazione mantenuta al di fuori di Angular. Potresti avere un filtro pre-filtro per impedire agli utenti non registrati di accedere all'html in cui è inserita la tua app Angular, e all'interno di quell'html puoi semplicemente interpolare il nome dell'utente collegato e persino il suo ID se desideri interagire con i dettagli dell'utente tramite richieste http dalla tua app Angular. È possibile consentire agli utenti non registrati di utilizzare l'App angolare con un 'utente ospite' predefinito. Qualsiasi consiglio sul perché questo approccio sarebbe negativo sarebbe il benvenuto - sembra troppo facile essere sensati!)


0

Questa è un'espansione dell'eccellente risposta di @Michael Tiller . La sua risposta funziona per inizializzare le variabili dalla vista iniettando l' $attrsoggetto nel controller. Il problema si verifica se viene richiamato lo stesso controller $routeProviderdurante la navigazione tramite routing. Quindi viene visualizzato l'errore dell'iniettore Unknown provider : $attrsProviderperché $attrsè disponibile per l'iniezione solo quando la vista viene compilata. La soluzione consiste nel passare la variabile (pippo) $routeParamsdurante l'inizializzazione del controller dalla rotta e l' $attrsinizializzazione del controller dalla vista. Ecco la mia soluzione

Dalla rotta

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

Questo gestisce un URL come '/mypage/bar'. Come puoi vedere, foo viene passato da url param e noi forniamo $injectorun oggetto vuoto per $attrsnessun errore dell'iniettore.

Dalla vista

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

</div>

Ora il controller

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'

});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.