Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFR] Clarify Map logic, allow nested fields #549

Merged
merged 19 commits into from
Jul 10, 2015
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ module.exports = function (grunt) {
options: {
port: 3000,
db: 'examples/blog/stub-server.json',
keepalive: false
keepalive: false,
logger: false
}
}
},
Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ Tell if the value is a link in the list view. Default to true for the identifier
Define the route for a link in the list view, i.e. `isDetailLink` of the field is true. The default is `edit`, hence the link points to the edition view. The other option is `show` to point to the show view.

* `map(function)`
Define a custom function to transform the value. It receive the value and the corresponding entry. Works in list, edit views and references.
Define a custom function to transform the value received from the API response to the value displayed in the admin. This function receives 2 parameters: the value to transform, and the corresponding entry. Works in list, edit views and references.

nga.field('characters')
.map(function truncate(value, entry) {
Expand All @@ -446,6 +446,24 @@ Define a custom function to transform the value. It receive the value and the co
.map(stripTags)
.map(truncate);

* `transform(function)`
Define a custom function to transform the value displayed in the admin back to the one expected by the API. This function receives 2 parameters: the value to transform, and the corresponding entry. Used in edit view only. Use it in conjunction with `map()` to ease the conversion between the API response format and the format you want displayed on screen.

// API
// map() v ^ tranform()
// Entry︎
//
// The API provides and expects last names in all caps, e.g. 'DOE'
// The admin should display them with capitalized last names, e.g 'Doe'
nga.field('last_name')
.map(function capitalize(value, entry) {
return value.substr(0,1).toUpperCase() + value.substr(1).toLowerCase()
})
.transform(function allCaps(value, entry) {
// the API expects upper case last names
return value.toUpperCase();
});

* `validation(object)`
Tell how to validate the view
- `required`: boolean
Expand Down
23 changes: 23 additions & 0 deletions UPGRADE-0.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,26 @@ admin.dashboard(nga.dashboard()
See the [Dashboard Configuration](doc/Dashboard.md) dedicated chapter for more details.

Calls to `dashboardView()` are still supported in ng-admin 0.8, but will raise an error in future versions.

## `field.map()` callbacks no longer apply to POST and PUT queries

Registering a transformation callback using `field.map()` used to be applied both ways: from the REST response to the Entry object used by ng-admin (in read queries using GET), and from the Entry object to the body of the REST requests (for write queries using POST and PUT). This didn't make sense, and prevented a proper use of this `map()` feature in the edition and creation view.

Now `map()` only applies to read queries, and a symmetric feature called `transform()` was added to handle the transformation of ng-admin values from forms to REST requests.

```js
// API
// map() v ^ tranform()
// Entry︎
//
// The API provides and expects last names in all caps, e.g. 'DOE'
// The admin should display them with capitalized last names, e.g 'Doe'
nga.field('last_name')
.map(function capitalize(value, entry) {
return value.substr(0,1).toUpperCase() + value.substr(1).toLowerCase()
})
.transform(function allCaps(value, entry) {
// the API expects upper case last names
return value.toUpperCase();
});
```
21 changes: 21 additions & 0 deletions doc/API-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,27 @@ app.config(function(RestangularProvider) {
}
```

**Tip**: If you want to define a field mapped to a deeply nested property, you don't need an interceptor. Just define the field with a name made by the path to the property using dots as separators:

```json
{
"id": 12,
"name": "War and Peace",
"author": {
"id": 345,
"name": "Leo Tolstoi"
},
"publication_date": "2014-01-01T00:00:00Z"
}
```

```js
listView.fields([
nga.field('name'),
nga.field('author.name')
])
```

## Pagination

ng-admin assumes that your API accepts `_page` and `_perPage` query parameters to paginate lists:
Expand Down
8 changes: 6 additions & 2 deletions examples/blog/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
// custom sort params
if (params._sortField) {
params._sort = params._sortField;
params._order = params._sortDir;
delete params._sortField;
delete params._sortDir;
}
// custom filters
if (params._filters) {
Expand Down Expand Up @@ -155,7 +157,8 @@
.fields([
nga.field('created_at', 'date')
.label('Posted'),
nga.field('author'),
nga.field('author.name')
.label('Author'),
nga.field('body', 'wysiwyg')
.stripTags(true)
.map(truncate),
Expand Down Expand Up @@ -186,7 +189,8 @@
nga.field('created_at', 'date')
.label('Posted')
.defaultValue(new Date()), // preset fields in creation view with defaultValue
nga.field('author'),
nga.field('author.name')
.label('Author'),
nga.field('body', 'wysiwyg'),
nga.field('post_id', 'reference')
.label('Post')
Expand Down
43 changes: 32 additions & 11 deletions examples/blog/stub-server.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,78 +183,99 @@
"comments": [
{
"id": 1,
"author": "Sigurd O'Conner",
"author": {},
"post_id": 6,
"body": "Queen, tossing her head through the wood. 'If it had lost something; and she felt sure it.",
"created_at": "2012-08-02"
},
{
"id": 2,
"author": "Kiley Pouros",
"author": {
"name": "Kiley Pouros",
"email": "kiley@gmail.com"
},
"post_id": 9,
"body": "White Rabbit: it was indeed: she was out of the ground--and I should frighten them out of its right paw round, 'lives a March Hare. 'Sixteenth,'.",
"created_at": "2012-08-08"
},
{
"id": 3,
"author": "Justina Hegmann",
"author": {
"name": "Justina Hegmann"
},
"post_id": 3,
"body": "I'm not Ada,' she said, 'and see whether it's marked \"poison\" or.",
"created_at": "2012-08-02"
},
{
"id": 4,
"author": "Ms. Brionna Smitham MD",
"author": {
"name": "Ms. Brionna Smitham MD"
},
"post_id": 6,
"body": "Dormouse. 'Fourteenth of March, I think I can say.' This was such a noise inside, no one else seemed inclined.",
"created_at": "2014-09-24"
},
{
"id": 5,
"author": "Edmond Schulist",
"author": {
"name": "Edmond Schulist"
},
"post_id": 1,
"body": "I ought to tell me your history, you know,' the Hatter and the happy summer days. THE.",
"created_at": "2012-08-07"
},
{
"id": 6,
"author": "Danny Greenholt",
"author": {
"name": "Danny Greenholt"
},
"post_id": 6,
"body": "Duchess asked, with another hedgehog, which seemed to be lost: away went Alice after it, never once considering how in the other. In the very tones of.",
"created_at": "2012-08-09"
},
{
"id": 7,
"author": "Luciano Berge",
"author": {
"name": "Luciano Berge"
},
"post_id": 5,
"body": "While the Panther were sharing a pie--' [later editions continued as follows.",
"created_at": "2012-09-06"
},
{
"id": 8,
"author": "Annamarie Mayer",
"author": {
"name": "Annamarie Mayer"
},
"post_id": 5,
"body": "I tell you, you coward!' and at once and put it more clearly,' Alice.",
"created_at": "2012-10-03"
},
{
"id": 9,
"author": "Breanna Gibson",
"author": {
"name": "Breanna Gibson"
},
"post_id": 2,
"body": "THAT. Then again--\"BEFORE SHE HAD THIS FIT--\" you never tasted an egg!' 'I HAVE tasted eggs, certainly,' said Alice, as she spoke. Alice did not like to have it.",
"created_at": "2012-11-06"
},
{
"id": 10,
"author": {
"name": "Logan Schowalter"
},
"post_id": 3,
"author": "Logan Schowalter",
"body": "I'd been the whiting,' said the Hatter, it woke up again with a T!' said the Gryphon. '--you advance twice--' 'Each with a growl, And concluded the banquet--] 'What IS the fun?' said.",
"created_at": "2012-12-07"
},
{
"id": 11,
"author": {
"name": "Logan Schowalter"
},
"post_id": 1,
"author": "Logan Schowalter",
"body": "I don't want to be?' it asked. 'Oh, I'm not Ada,' she said, 'and see whether it's marked \"poison\" or not'; for she had asked it aloud; and in despair she put her hand on the end of the.",
"created_at": "2012-08-05"
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"npm": "^2.10.0"
},
"devDependencies": {
"admin-config": "^0.2.4",
"admin-config": "marmelab/admin-config#map_transform",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

admin-config 0.2.5 version had been published.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched dependency to fixed version

"angular": "~1.3.15",
"angular-bootstrap": "^0.12.0",
"angular-mocks": "1.3.14",
Expand Down Expand Up @@ -47,7 +47,7 @@
"grunt-contrib-uglify": "~0.6.0",
"grunt-contrib-watch": "~0.5.2",
"grunt-exec": "^0.4.6",
"grunt-json-server": "git://github.com/fzaninotto/grunt-json-server.git#c834e50e2151a16930f1378324cf96b91438bdae",
"grunt-json-server": "git://github.com/fzaninotto/grunt-json-server.git",
"grunt-karma": "^0.8.3",
"grunt-mocha-test": "^0.12.7",
"grunt-ng-annotate": "^0.10.0",
Expand Down
37 changes: 14 additions & 23 deletions src/javascripts/ng-admin/Crud/button/maExportToCsvButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
define(function () {
'use strict';

function maExportToCsvButton ($stateParams, Papa, notification, entryFormatter, ReadQueries) {
function maExportToCsvButton ($stateParams, Papa, notification, AdminDescription, entryFormatter, ReadQueries) {
return {
restrict: 'E',
scope: {
Expand Down Expand Up @@ -37,34 +37,28 @@ define(function () {
var optimizedReferencedData;

ReadQueries.getAll(exportView, -1, scope.search(), $stateParams.sortField, $stateParams.sortDir)
.then(function (response) {
.then(response => {
rawEntries = response.data;

return rawEntries;
}, function (error) {
notification.log(error.message, {addnCls: 'humane-flatty-error'});
})
.then(function (rawEntries) {
return ReadQueries.getFilteredReferenceData(exportView.getNonOptimizedReferences(), rawEntries);
})
.then(function (nonOptimizedReference) {
.then(rawEntries => ReadQueries.getFilteredReferenceData(exportView.getNonOptimizedReferences(), rawEntries))
.then(nonOptimizedReference => {
nonOptimizedReferencedData = nonOptimizedReference;

return ReadQueries.getOptimizedReferencedData(exportView.getOptimizedReferences(), rawEntries);
})
.then(function (optimizedReference) {
.then(optimizedReference => {
optimizedReferencedData = optimizedReference;

var references = exportView.getReferences(),
referencedData = angular.extend(nonOptimizedReferencedData, optimizedReferencedData),
referencedEntries;

for (var name in referencedData) {
referencedEntries = scope.datastore.mapEntries(
references[name].targetEntity().name(),
references[name].targetEntity().identifier(),
referencedEntries = AdminDescription.getEntryConstructor().createArrayFromRest(
referencedData[name],
[references[name].targetField()],
referencedData[name]
references[name].targetEntity().name(),
references[name].targetEntity().identifier().name()

);

scope.datastore.setEntries(
Expand All @@ -74,12 +68,7 @@ define(function () {
}
})
.then(function () {
var entries = scope.datastore.mapEntries(
exportView.entity.name(),
exportView.identifier(),
exportView.getFields(),
rawEntries
);
var entries = exportView.mapEntries(rawEntries);

// shortcut to diplay collection of entry with included referenced values
scope.datastore.fillReferencesValuesFromCollection(entries, exportView.getReferences(), true);
Expand All @@ -95,13 +84,15 @@ define(function () {
fakeLink.setAttribute('href', 'data:application/octet-stream;charset=utf-8,' + encodeURIComponent(csv));
fakeLink.setAttribute('download', scope.entity.name() + '.csv');
fakeLink.click();
}, function (error) {
notification.log(error.message, {addnCls: 'humane-flatty-error'});
});
};
}
};
}

maExportToCsvButton.$inject = ['$stateParams', 'Papa', 'notification', 'EntryFormatter', 'ReadQueries'];
maExportToCsvButton.$inject = ['$stateParams', 'Papa', 'notification', 'AdminDescription', 'EntryFormatter', 'ReadQueries'];

return maExportToCsvButton;
});
2 changes: 1 addition & 1 deletion src/javascripts/ng-admin/Crud/field/maField.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ define(function (require) {
scope.datastore = scope.datastore();

scope.getClassesForField = function(field, entry) {
return 'ng-admin-field-' + field.name() + ' ' + (field.getCssClasses(entry) || 'col-sm-10 col-md-8 col-lg-7');
return 'ng-admin-field-' + field.name().replace('.', '_') + ' ' + (field.getCssClasses(entry) || 'col-sm-10 col-md-8 col-lg-7');
};

scope.getInputForField = function(field) {
Expand Down
Loading