问题
I am wondering how to include parameters when changing state and sending the request to get the template from the backend.
Here is my app:
angular.module('questionnaireApp', ['ngAnimate', 'ui.router', 'ui.bootstrap'])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('questionnaire', {
url: '/questionnaire',
templateUrl: 'questionnaire/questionnaire.html',
controller: 'questionnaireCtrl'
})
.state('questionnaire.receiver_name', {
url: '/receiver_name',
templateUrl: 'questionnaire/receiver_name.html'
})
.state('questionnaire.location', {
url: '/location',
templateUrl: 'questionnaire/location.html'
})
.state('poem', {
url: '/poem',
templateUrl: 'questionnaire/poem.html',
controller: 'questionnaireCtrl'
});
$urlRouterProvider.otherwise('/questionnaire/receiver_name');
}])
.controller('questionnaireCtrl', ['$scope', '$http', '$state', function($scope, $http, $state) {
$scope.formData = {};
}]);
I am saving user input in $scope.formData
. I need to include it in my request to be able to render questionnaire/poem.html
.
Something like:
.state('poem', {
url: '/poem',
templateUrl: 'questionnaire/poem' + $scope.formData + '.html',
controller: 'questionnaireCtrl'
});
How can I do that?
Or is there any variant that can help me send the formData to my backend so that it can render the poem.html page properly?
回答1:
You can do it by making the templateUrl a function. Take a look at this example, taken from ui-router documentation ( https://github.com/angular-ui/ui-router/wiki ):
$stateProvider.state('contacts', {
templateUrl: function ($stateParams){
return '/partials/contacts.' + $stateParams.filterBy + '.html';
}
})
In the above example, we get $stateParams as an argument (note, it's not an injection, more details on the doc site) and use the parameter "filterBy" as part of the template url. In your case, it's formData.
Note 1: You must pass a string. If formData is an object, you can't use it as part of the templateUrl, and you probably won't be able to even pass it as part of the stateParams. maybe you want a specific field from it? Something like 'formType'?
Note 2: As mb21 mentioned, all of this has nothing to do with the backend. if you want to send the form data, do a REST call. Routing should involve only the client side.
回答2:
questionnaire/poem.html
should be an Angular html template file, nothing dynamically generated by the server.
To save your data, use Angular's http service to do a post request to the server that wants the data.
If you have the data on PageA with ControllerA and need to have it on PageQ with ControllerQ, you should share the data using a factory between the two controllers. No need to involve the server.
回答3:
I finally managed to achieve my goal: retrieve the poem with one HTTP request only.
To do that:
- I store the HTML templates inside the Angular app so that it only needs to retrieve JSON data
- form data is sent with regular http post
- poem data is sent back in JSON format
- the poem is displayed thanks to Angular data binding
Angular code:
angular.module('thePoetApp').config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/questionnaire)
.state('questionnaire', {
url: '/questionnaire',
templateUrl: 'questionnaire/questionnaire.html',
})
// nested states
// each of these sections will have their own view
// url will be nested (/questionnaire/receiver_name)
.state('questionnaire.receiver_name', {
url: '/receiver_name',
template: '<div class="col-md-3 text-left ng-scope"></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group"><label for="receiver_name">Receiver Name:</label><input name="receiver_name" ng-model="formData.receiver_name" receiver_name="receiver_name" required="" type="text" class="ng-pristine ng-invalid ng-invalid-required"></div><div class="form-group"><label for="receiver_sex">Receiver Sex:</label><input name="receiver_sex" ng-model="formData.receiver_sex" receiver_sex="receiver_sex" required="" type="radio" value="male" class="ng-pristine ng-invalid ng-invalid-required">Male<input name="receiver_sex" ng-model="formData.receiver_sex" receiver_sex="receiver_sex" required="" type="radio" value="female" class="ng-pristine ng-invalid ng-invalid-required">Female</div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.location">Next Step</a></div>',
})
// url will be /questionnaire/location
.state('questionnaire.location', {
url: '/location',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.receiver_name">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group"><label for="location">Location:</label><input location="location" name="location" ng-model="formData.location" required="" type="text" class="ng-pristine ng-invalid ng-invalid-required"></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.relationship">Next Step</a></div>'
})
// url will be /questionnaire/relationship
.state('questionnaire.relationship', {
url: '/relationship',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.location">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="RelationshipsTypeaheadCtrl"><label for="relationship">Relationship:</label><input autocomplete="off" name="relationship" ng-model="formData.relationship" relationship="relationship" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in relationships($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.trait">Next Step</a></div>'
})
// url will be /questionnaire/trait
.state('questionnaire.trait', {
url: '/trait',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.relationship">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="TraitsTypeaheadCtrl"><label for="trait">Trait:</label><input autocomplete="off" name="trait" ng-model="formData.trait" trait="trait" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in traits($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div><div class="col-md-3 text-right ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.message">Next Step</a></div>'
})
// url will be /questionnaire/message
.state('questionnaire.message', {
url: '/message',
template: '<div class="col-md-3 text-left ng-scope"><a class="btn btn-primary" ui-sref="questionnaire.trait">Previous Step</a></div><div class="form-container col-md-6 text-center ng-scope"><div class="form-group ng-scope" ng-controller="MessagesTypeaheadCtrl"><label for="message">Message:</label><input autocomplete="off" name="message" ng-model="formData.message" message="message" required="" type="text" typeahead-editable="false" typeahead="suggestion for suggestion in messages($viewValue)" class="ng-pristine ng-invalid ng-invalid-required"><ul class="dropdown-menu ng-isolate-scope"><!-- ngRepeat: match in matches --></ul></div></div>'
})
.state('poem', {
url: '/poem',
template: '<div class="poem"><p>{{ poem.title }}</p><p><div>{{ poem.intro_verse.line_one}}</div><div>{{ poem.intro_verse.line_two}}</div><div>{{ poem.intro_verse.line_three}}</div><div>{{ poem.intro_verse.line_four}}</div><div>{{ poem.intro_verse.line_five}}</div></p><p><div>{{ poem.trait_verse.line_one}}</div><div>{{ poem.trait_verse.line_two}}</div><div>{{ poem.trait_verse.line_three}}</div><div>{{ poem.trait_verse.line_four}}</div><div>{{ poem.trait_verse.line_five}}</div></p><p><div>{{ poem.message_verse.line_one}}</div><div>{{ poem.message_verse.line_two}}</div><div>{{ poem.message_verse.line_three}}</div><div>{{ poem.message_verse.line_four}}</div><div>{{ poem.message_verse.line_five}}</div></p><div class="text-center"><a class="btn btn-warning" ui-sref="questionnaire.receiver_name">Restart</a></div></div>'
});
// catch all route
// send users to the receiver_name page
$urlRouterProvider.otherwise('/questionnaire/receiver_name');
Angular controller:
postParams =
{"questionnaire":
{
"receiver_name": $scope.formData.receiver_name,
"receiver_sex": $scope.formData.receiver_sex,
"location": $scope.formData.location,
"relationship": $scope.formData.relationship,
"trait_category": $scope.formData.trait,
"message_category": $scope.formData.message
}
}
// send post request
$http({
method : 'POST',
url : 'api/questionnaire/poem',
data : $.param(postParams), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
})
.success(function(data) {
if (data.success) {
$scope.poem = data.poem;
$scope.formData = {};
$state.go('poem');
}
});
$scope.poem = data.poem'
sets the poem data so that {{ poem.title }}
and so on get replaced when going to the poem
state.
来源:https://stackoverflow.com/questions/24588086/dynamic-parameters-with-angular-ui-router