Frequently Asked Questions

My API exposes X-Total-Count but ng-admin doesn't see it

If you added the X-Total-Count header to your API but the pagination controls don't appear, maybe it's a cross-origin resource sharing (CORS) problem.

The admin application is probably hosted on another domain than the API, so you must explicitly allow the access to the header from the admin app domain. To do so, add a Access-Control-Expose-Headers: x-total-count header to the API response.

My API requires Authentication. How Can I Set it up?

Many API require some sort of authentication, for instance Basic HTTP Authentication, which only accepts requests to the API including an Authorization header looking like:

Authorization Basic YWRtaW46cGFzc3dvcmQ=

...where the token after Basic is base64(username + ':' + password).

To add such a token, you must modify the default headers in Restangular, as explained in the API Mapping documentation.

myApp.config(function(RestangularProvider) {
    var login = 'admin',
        password = '53cr3t',
        token = window.btoa(login + ':' + password);
    RestangularProvider.setDefaultHeaders({'Authorization': 'Basic ' + token});
});

If the login and password must be entered by the end user, it's up to you to ask for login and password in another page, store them in localStorage/sessionStorage, change the location to ng-admin's app, and grab the login and password from storage when ng-admin is initialized.

You can find an example login page with fake authentication in the Posters Galore demo.

How Can I Display A Composite Field?

If your API sends users with a firstName and a lastName, you may want to compose these properties into a composite field.

{
    "id": 123,
    "firstName": "Leo",
    "lastName": "Tolstoi",
    "occupation": "writer"
}

That's quite easy: create a field with the name of a non-existing property, and use Field.map(value, entry) to do so:

user.listView().fields([
    nga.field('id'),
    nga.field('fullname')
        .map(function(value, entry) {
            // value is undefined since there is no entry.fullname
            // entry contains the entire set of properties
            return entry.firstName + ' ' + entry.lastName;
        })
])

How Can I Map Twice The Same Field In A List?

If your API sends a piece of data that you want to display twice in a different way, you may hit a wall. For instance:

post.listView().fields([
    nga.field('id'),
    nga.field('user_id', 'reference')
        .label('Author first name')
        .targetEntity(user)
        .targetField(nga.field('firstName'),
    nga.field('user_id', 'reference')
        .label('Author last name')
        .targetEntity(user)
        .targetField(nga.field('lastName'),

This doesn't work, because ng-amin imposes a unicity constraint on field names. Since there are two fields named user_id, it's a blocker.

The solution is to duplicate the property in an ElementTransformer:

myApp.config(function(RestangularProvider) {
    RestangularProvider.addElementTransformer('posts', function(element) {
        element.user_id_2 = element.user_id;
        return element;
    });
});

Now you can have two fields with the same value but different names:

post.listView().fields([
    nga.field('id'),
    nga.field('user_id', 'reference')
        .label('Author first name')
        .targetEntity(user)
        .targetField(nga.field('firstName'),
    nga.field('user_id_2', 'reference')
        .label('Author last name')
        .targetEntity(user)
        .targetField(nga.field('lastName'),

How Can I Handle Server-Side Validation?

Some field validation can't be done on the client side, and require a roundtrip to the server. For instance, a POST /comment REST endpoint may return with an HTTP error code if the post_id pointed by the new comment doesn't exist.

POST /comment
{
    body: 'Commenting on a non-existent post',
    post_id: 123
}

HTTP 1.1 400 Bad Request
[
    { propertyPath: 'post_id', message: 'Related post does not exist' }
]

To catch these errors and display them, use the editionView.onSubmitError() and creationView.onSubmitError() hooks. They accept an angular injectable (a function listing its dependencies), and ng-admin can inject the error response, the form object, and many other useful services.

comment.editionView().onSubmitError(['error', 'form', 'progression', 'notification', function(error, form, progression, notification) {
    // mark fields based on errors from the response
    error.violations.forEach(violation => {
        if (form[violation.propertyPath]) {
            form[violation.propertyPath].$valid = false;
        }
    });
    // stop the progress bar
    progression.done();
    // add a notification
    notification.log(`Some values are invalid, see details in the form`, { addnCls: 'humane-flatty-error' });
    // cancel the default action (default error messages)
    return false;
}]);

results matching ""

    No results matching ""