vendredi 27 mars 2015

Angular Form Update Collection Data

I'm still new to angular, and I think handling form is the biggest challenge, especially for collection data (PUT/update). FYI I'm using ui-router and $resource.


I have Category model which could have a lot of translations for its name and description. The structure if I call GET request to /categories/1 is:


GET /categories/1



{
id: 1,
translations: [
{
id: 1,
language: {
id: 1,
name: 'English',
code: 'en'
},
name: 'Book', // Category Name
description: 'Book Description'
},
{
id: 2,
language: {
id: 2,
name: 'Indonesian',
code: 'id'
},
name: 'Buku',
description: 'Deskripsi Buku'
}
]
}


Controller



angular
//...
.controller('CategoryEditController', ['$stateParams', '$scope', 'Category', 'Language',
function($stateParams, $scope, Category, Language) {
var categoryId;
$scope.category = {};
$scope.languages = [];

Language.query(function(data) {
$scope.languages = data;
});

Category.get({id: $stateParams}, function(data) {
$scope.category = data;
categoryId = data.id;
}

$scope.save = function() {
Category.update({id: categoryId}, $scope.category,
function(data) {
console.log('Update successful');
}
);
};
}
])


This is the controller for editing the Category data. But this did not work for me. Because our API need the category prefix and can not contain extra fields. This is how our PUT request data should be in JSON:



{
category : {
translations: [
{
name: 'Book',
description: 'Book Description',
language: 1 /* Language id */
},
{
name: 'Buku',
description: 'Deskripsi Buku',
language: 2 /* Language en */
},
]
}
}


As you can see the differences between the category data we get via GET API and the request data we need for the PUT API. If we send the data directly, we would get validation error and extra fields error.


Why we need the 'category' prefix? Because the API use symfony2 form, and automatically name the form with 'category' prefix (category[translations][o][name]).


Why it couldn't contain extra fields? Because it's part of symfony2 validation and it would trigger the validation error.


This is how I handle this problem inside the controller:



angular
//...
.controller('CategoryEditController', ['$stateParams', '$scope', 'Category', 'Language',
function($stateParams, $scope, Category, Language) {
var categoryId;
$scope.category = {};
$scope.category.translations = []; // Define translations as array
$scope.languages = [];

Language.query(function(data) {
$scope.languages = data;

for (var i=0; i<data.length; i++) {
// Define Available Translations
$scope.category.translations[i] = {
language: data.id
};
}
});

Category.get({id: $stateParams}, function(data) {
for (var i=0; i<data.translations.length; i++) {
for (var j=0; j<$scope.languages.length; j++) {
if ($scope.languages[j].id = data.translations[i].language.id) {
$scope.category.translations[j] = {
name: data.translations[i].name,
description: data.translations[i].description,
language: data.translations[i].language.id
};
}
}
}
categoryId = data.id;
}

$scope.save = function() {
Category.update({id: categoryId}, $scope.category,
function(data) {
console.log('Update successful');
}
);
};
}])


My solution works! But if I have a lot of other CRUD I need to make, it would become very ugly. Should I keep doing this? or is there any other available solution? I already googled several times, but nothing relevant.


And also, is there anyway to bind the model for the form with the category data we got from the resource query? As you can see, I used multiple loops to make sure that the data bind to the correct index of the translations. The order could be English then Indonesian, or Indonesian then English.


Sorry if my explanation is not that clear. I'm just trying to get some help and very curious about handling this angular form.


Form



<form ng-submit="save()">
<div ng-repeat="language in languages">
<label> Name {{ language.code | uppercase }} :
<input ng-model="category.translations[$index].name" />
</label>
</div>
<div ng-repeat="language in languages">
<label> Name {{ language.code | uppercase }} :
<input ng-model="category.translations[$index].description" />
</label>
</div>
</form>


For the input, I use languages as the iterator, so it'll display all the available languages. But the problem is, I can't send a POST or PUT request with a null name or description in the translations.



{
translations: [
{
name: 'Book',
description: 'Book Description',
language: 1
},
{
language: 2
}
]
}


it would fail the validation, because the second translation name and description is undefined. That's why I need to delete any translation with null name or description before I send the request. Obviously, it would be very ugly too, but it works.


If you have any solution, even resources I could read to understand how to solve this, I would be very happy and I hope it could help others who also using angular js.


Aucun commentaire:

Enregistrer un commentaire