GithubHelp home page GithubHelp logo

jakubrohleder / angular-jsonapi Goto Github PK

View Code? Open in Web Editor NEW
96.0 96.0 34.0 4.46 MB

Simple and lightweight, yet powerful ORM for your frontend that seamlessly integrates with your JsonAPI server.

Home Page: http://jakubrohleder.github.io/angular-jsonapi/

License: GNU General Public License v3.0

JavaScript 99.31% HTML 0.69%

angular-jsonapi's People

Contributors

jakubrohleder avatar lavatoaster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

angular-jsonapi's Issues

Reg type of the schema object - singular vs plural

In the docs it is mentioned that the type of the schema object must be plural.

Type of an object must be the same as the one in the JSON API response. Should be in plural.

Is this a hard requirement? I have an endpoint in plural say /articles but the type is in singular form article. The schema object is as follows:

var articleSchema = {
  type: 'article',
  id: 'int',
  attributes: {
    title: {presence: true},
    content: {presence: true}
  },
  relationships: {}
};

var restSynchro = $jsonapi.sourceRest.create('Rest synchronization', 'http://localhost:3000/api/articles');
var synchronizer = $jsonapi.synchronizerSimple.create([restSynchro]);
$jsonapi.addResource(articleSchema, synchronizer);

The above code throws up this error:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.4.8/$rootScope/infdig?p0=10&p1=%5B%5D
    at REGEX_STRING_REGEXP (http://localhost:3001/bower_components/angular/angular.js:68:12)
    at Scope.parent.$get.Scope.$digest (http://localhost:3001/bower_components/angular/angular.js:15934:19)
    at Scope.parent.$get.Scope.$apply (http://localhost:3001/bower_components/angular/angular.js:16160:24)
    at bootstrapApply (http://localhost:3001/bower_components/angular/angular.js:1679:15)
    at Object.invoke (http://localhost:3001/bower_components/angular/angular.js:4523:17)
    at doBootstrap (http://localhost:3001/bower_components/angular/angular.js:1677:14)
    at bootstrap (http://localhost:3001/bower_components/angular/angular.js:1697:12)
    at angularInit (http://localhost:3001/bower_components/angular/angular.js:1591:5)
    at HTMLDocument.<anonymous> (http://localhost:3001/bower_components/angular/angular.js:29013:5)
    at jQuery.Callbacks.fire (http://localhost:3001/bower_components/jquery/dist/jquery.js:3099:30) undefined

Changing the type to plural articles seems to work. What am I missing?

Unlink method leaves relationships object empty

When I call the 'unlink' method of an element, it seems to set empty the whole element's relationship attribute when request is made. For example, having the following schemas:

// Factory schema

      {
          type: 'factories',
          attributes: {
            name: {}
          },
          include: {
            all: [
              'users',
            ],
            get: [
              'users',
            ],
          },
          relationships: {
            users: {
              included: false,
              model: 'users',
              reflection: 'factory',
              type: 'hasMany',
            },
        }

// User schema

      {
          type: 'users',
          attributes: {
            name: {}
          },
          include: {
            all: [
              'factory',
            ],
            get: [
              'factory',
            ],
          },
          relationships: {
            factory: {
              included: false,
              model: 'factories',
              reflection: 'users',
              type: 'hasOne',
            },
        },

Now, the 'unlink' of a 'factory' in a 'user', it'd look like this:

// Assuming 'factory' as a angular-jsonapi object
// with type: 'factories' and id: '2'
// and 'user' with type: 'users' and id: '1'
user.form.unlink('factory', factory);

When the user.save() is executed, the user's relationship attribute in the request is empty and doesn't remove the relationship:

// request content object
{
   "data":{
      "id":"1",
      "type":"users",
      "attributes":{
          "name": "eduard"
      },
      "relationships":{
        /**
          * should have:
          * factory: { data: null }
          * but it's empty
          */
      }
   }
}
  1. Am I doing anything wrong or is there a problem in the unlink method?
  2. In the docs it's not clear what 'target' represents on unlink method, I just assumed it was an angular-jsonapi object, but I don't know what it really means.

Thanks in advance.

Retrieving large data set of relationships

Quick example:

{ type: "blog", id: "XX", relationships: { posts: [ Array of 10000] } }

Querying such an object from REST-API including 10000 posts could hang the application.

For such a case, it would be great to retrieve posts from a specific api endpoint:

/update/XX/posts

Any ideas?

Setting custom headers

As far I can see, it is not possible to set a custom header for the resources calls, right? If not, is there any workaround?

Thanks!

ReferenceError: Parse is not defined

Simply including the source file (min or not) doesn't work for me, it looks like it's utilizing a global var that's not defined:

(function() {
  'use strict';

  /* global Parse: false */
  angular.module('angular-jsonapi-parse', ['angular-jsonapi'])
    .constant('Parse', Parse);
})();

Went to run the demo with gulp serve as the documentation suggested to see if I could find out more, but that's not working either... I just get Cannot get /.

EDIT

Looks like this is just poorly documented and needs the following prior to launch:

<script src="lib/parse/parse.min.js"></script>
<script src="lib/pluralize/pluralize.js"></script>
<script src="lib/validate/validate.min.js"></script>
<script src="lib/angular-uuid4/angular-uuid4.min.js"></script>

That said, why do we need to include parse even if we don't want to use parse? Can't you conditionally set the constant so we don't have to include parse just to appease a module we're not using, or hack it e.g. <script>window.Parse = { iShould: 'notBeNeeded' };</script>?

Promise Undefined :´(

Hey guys.

I'm having a problem with the next code:

resource.all(params).promise.then(resolve => {
    $log.info(resolve); // the result is undefined
});

This return me the message: 'undefined'.
someone has idea why is this happening?

PATCH vs PUT

Of.spec claims to send PATCH request to update existing records instead of PUT.
It also says that only updated attributes/relationships should be sent.

Updating a Resource's Attributes
PATCH /articles/1 HTTP/1.1

link

Also, it could significantly decrease amount of data we're sending to the back-end.

Nested resources

Hi there, its more of a questions, since its not that clear so far. But how does it deal with nested resources like /users/:id/phones? I can only see that you can include phones, but not call that resource directly.

Thanks!

Improvements

Place for discussions about possible improvements / additions / api or roadmap changes for the package.

Live Demo seems to be down

Hi, this looks pretty cool and am really interested in this, just wanting to play a bit with the live demo, but it seems to broken : http://jakubrohleder.github.io/angular-jsonapi/

In the console I see :

Error: [$injector:unpr] Unknown provider: eProvider <- e <- $q
http://errors.angularjs.org/1.4.3/$injector/unpr?p0=eProvider%20%3C-%20e%20%3C-%20%24q

Any change to get it working?

Support for Server Side Events through WebSockets

My current implementation sends updates to connected clients when events occur on the server:

Update format:

For a create:

{
  "data": {
    "type": "organization",
    "id": "500"
  },
  "meta": {
    "update_type": "CREATE",
  }
}

For A change:

{
  "data": {
    "type": "organization",
    "id": "500",
    "attributes": {
      "permissions": {
        "change": true,
        "view": true,
        "add": true,
        "delete": true
      },
      "created_at": "2015-09-25T19:59:40.422528Z",
      "modified_at": "2015-09-25T19:59:49.607210Z",
      "name": "11111",
      "nickname": null,
      "reference": "111001",
      "notes": null
    },
    "relationships": {
      "children": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/children",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/children"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "parent": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/parent",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/parent"
        },
        "data": null
      },
      "resellers": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/resellers",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/resellers"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "customers": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/customers",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/customers"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "departments": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/departments",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/departments"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "people": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/people",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/people"
        },
        "data": [
          {
            "type": "person",
            "id": "1162"
          },
          {
            "type": "person",
            "id": "1019"
          },
          {
            "type": "person",
            "id": "1390"
          },
          {
            "type": "person",
            "id": "771"
          },
          {
            "type": "person",
            "id": "1548"
          }
        ],
        "meta": {
          "count": 5
        }
      },
      "administrators": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/administrators",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/administrators"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "email_domains": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/email_domains",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/emaildomains"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "phone_numbers": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/phone_numbers",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/phonenumbers"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "email_addresses": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/email_addresses",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/emailaddresses"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      },
      "urls": {
        "links": {
          "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/relationships/urls",
          "related": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500/urls"
        },
        "data": [],
        "meta": {
          "count": 0
        }
      }
    },
    "links": {
      "self": "http://api-dev.zerofail.com:8080/api/contacts/organizations/500"
    }
  },
  "meta": {
    "update_type": "UPDATE",
  }
}

For A delete:

{
  "data": {
    "type": "organization",
    "id": "500"
  },
  "meta": {
    "update_type": "DELETE",
  }
}

The reason why the object is not send with the creation is that it gives a notification instead of the actual data - This permits a validation of the required permissions on the server side when client GETs the object(s).

Remote add/update object with relationships in only one transaction

Hi!

We need add/update relational objects but in just only one transaction.

For example,

    var schema = {
      type: 'cars',
      id: 'string',
      attributes: {
        name: {presence: true}
      },
      relationships: {
        wheels: {
          included: true,
          type: 'hasMany'
        }
      }
   }

We need save car and the wheels, but if the wheels fail, car object should not be saved. The server evaluate object as a whole, not as simple parts.

In other words, we need just only one HTTP request for the car and wheels.

Of course, the example is for didactic purposes only.

Regards...

AngularJsonApiResource.get - data for the resolved promise?

Description

I've just started messing around with this library. I was able to get things setup pretty quickly and define a schema for a couple of my resources. Testing in the debug console yielded what I was expecting out of it.

In our app, we use a resolve in one of our routes before moving on. I noticed that the AngularJsonApiResource.get method has a promise value that is returned; I expected that the resolved promise that came back would actually have the same object that is returned from the get, but it doesn't. It is undefined.

To be clear, the promise resolves accordingly, but it appears that what is actually resolved is the response.data.meta, vs. the object that I expected.

Am I understanding incorrectly how this should work?

Don't include relationship if type "hasMany"

const admterritorySchema = {
    type: 'admterritory',
    id: 'string',
    attributes: {
      // ...
    },
    relationships: {
        population: {
            included: true,
            type: 'hasMany',
            model: 'population',
            reflection: false
        }
    }
};

If I write 'hasOne' in type, it will send request like /admterritory?include=population and it's good. But if I write 'hasMany', it sends request without include in query

Synchronization docs saying constructors take 1 parameter

Docs shows this constructor with 1 parameter;

var localeSynchronization = new AngularJsonAPISynchronizationLocal('AngularJsonAPI');
var restSynchronization = new AngularJsonAPISynchronizationRest('/novels');

however, there're 2 in the code

Q&A

Topic for questions about the package usage that does not require a new issue. Feel free to ask about anything!

Trailing slash

This line creates a trailing slash. Is it possible to make it optional? Other URL calls in this project don't have a trailing slash

"TypeError: Cannot read property 'cache' of undefined" with 'include'

Hi, again.

I was configuring my schema and making tests with 'include' option, having my schema with something like this:

var schema = {
  type: 'users',
  attributes: { ... },
  include: {
    all: ['factory'],
    get: ['factory'],
  },
}

Then, I execute resource's all() method, the request is made successfully and the server gives the results with 'data' and 'included' as JSON API spec says, but just right after that, this error appears:

TypeError: Cannot read property 'cache' of undefined

What could the problem be?

Thanks in advance.

P.D.: Tested in Chrome.

Uncaught ReferenceError: Parse is not defined

When I install the library in my project, console says:

Uncaught ReferenceError: Parse is not defined

I follow these steps:

bower install angular-jsonapi --save

and I add this modules to my project

        'angular-jsonapi',
        'angular-jsonapi-rest',
        'angular-jsonapi-local',
        'angular-jsonapi-parse',

Any ideas? Thanks....

Support for pagination

Of.spec has a statement regarding pagination

A server MAY choose to limit the number of resources returned in a response to a subset ("page") of the whole set available.

A server MAY provide links to traverse a paginated data set ("pagination links").

Pagination links MUST appear in the links object that corresponds to a collection. To paginate the primary data, supply pagination links in the top-level links object. To paginate an included collection returned in a compound document, supply pagination links in the corresponding links object.

The following keys MUST be used for pagination links:

first: the first page of data
last: the last page of data
prev: the previous page of data
next: the next page of data

here

Do you have plans to support pages?

Tag more frequently

I'm keeping up to date with changes with the packages, however in the past 7 days you've introduced some pretty cool features and fixed some restrictions, but they're untagged. To be able to use them I need to override my bower config to include the newest commit hash.

I suggest changing how you're currently versioning the alpha packages, as in my opinion it is a little awkward and less than semantic. Such as versioning under 1, using versions similar to 0.0.1 and such. So breaking changes result in 0.1.0 being released, and new features 0.1.1 and such.

I get that it's an alpha/in-dev package and you're not recommending anyone to use it in production however this is the only angular package that I've seen to properly support the spec and make it easy to use.

How to tackle local storage limit?

I recently learned quite an interesting fact I've never thought about - the limit of local storage is quite low (approx. 5200000B~=5MB for chrome), exceeding this limit can produce weird results and might be a problem for bigger apps.

I have two ideas but non of it seems to be perfect:

  • compressing data - I tried compressing data with LZW compression, but out of the box it significantly slowed the performance of the package. Each time the model is fetched its key, as well as its relationship keys are dumped to localstore (and compressed).
    The one solution I can find is to dump cached data to localstore, not during each request but in some time intervals and during $rootScope destroy event. It requires some work so I prefer to think it through before writing the code.
  • storing newest data only - some data can be removed from the locastore using cache algorithm or something similar. Question is: which algorithm to choose to provide the best user experience?

Do you find it a high priority issue? Can you find any other solutions?

How to use JsonApi factory injected into controller

@jakubrohleder We are using your JsonApi in a slightly different way to your Demo App.
We are injecting an accounts resource factory (return $jsonapi.getResource('accounts')) into our controller and using accounts.all().promise to get a collection of accounts.

On the return of the promise, we populate our view model using vm.accountsList = accounts.cache.index(). Is this an acceptable way to use the JsonApi?

I know this is a different approach to your demo app, but we just want to make sure we are not making any fundamental mistakes.
Any help appreciated.
Regards, Paul

We migrated from angular-jsonapi to ts-angular-jsonapi

We are very grateful with @jakubrohleder, we use this library for 6 months. But, today, it's time to move on. Like you know, angular-jsonapi is the best on the angular-ecosystem but the absence of activity here (pull requests, unsolved problems #45 and abandoned roadmap, for example) we decided to create our own library:

ts-angular-jsonapi

ts-angular-api is not a better or worst library, it's just an another focus of this problem: get jsondata from a a server.

We decided, for example, for typescript (best choose on angular2), and improve for especific problem on our project.

If you prefer this approach, you are welcome.

Write documentation

You seem to have a great project going on and it would be nice to have a description of what it can do if possible :)

Is it currently in a working state? Can the library be used in my projects as well? So many questions!

Retrieve data only from cache without request

Hi.

More than a issue is a question. I noticed when I execute resource's all() method, it makes a request to the REST server automatically, even if I only want to take data from cache. For example:

// Factory

factory.publicData = [];

// Store in collection what it found in cache but makes the request anyway
var collection = resource.all();

// Make the public assignment to be used by controllers or another factory
factory.publicData = collection.data;

// if I want the updated data, I have to use the promise but the request was made
// even if I didn't want to use the promise
collection.promise.then(
  function success() {
     factory.publicData = collection.data;
  }
);

I want to avoid a lot of unnecessary requests to REST server because my app is big. Is there a way to use all() method without making the request and retrieving only cache data?

Error.captureStackTrace is not a function

In the source and validation error factories, a call is made to Error.captureStackTrace which doesn't exist in a normal browser.

It causes any validation errors that happen to error out.

I'm unsure if you meant to use something else there, or if they're a relic from something else, so I didn't submit a PR for this.

How to deserialize

I need a way to tell the resource API to deserialize server sent dates as strings ("2016-05-13") into javascript dates so angular-material datepicker doesn't wine about model being an string.

I can't seem to find a way to do this without getting deep into the source of the package. Do you know a simple way to do this?

Currently I'm doing this to override resource's initialize function:

// ....
function factoryConstructor($jsonapi) {
  var resource = $jsonapi.getResource("expenditure");

  resource.initialize = function() {
    var res = this.__proto__.initialize.apply(this);
    res.form.data.attributes["expent-at"] = new Date();
    return res;
  }

  return resource;
}

I would be cool if I could override another function like deserialize(jsonObj) to make this work.

Dependency injection and strict mode problem

Hi. I've recently updated the package with bower but it throws an error about strict mode and dependency injection. All worked well on alpha.4 but I made the update and it broke. Also I noticed you updated bower.json file to alpha.6 version but when I make the update, it shows alpha.5. Is anything wrong with the file or in somewhere else? Does the alpha.6 fix the D.I. error?

Thanks in advance.

One resource, different REST endpoints

I'm wondering if there is a way to synchronise a resource in a conditional way. Since I have resources that can be modified from different end points. For example:

Resource: Organizations

You can GET organizations doing: api.com/organizations or you can do api.com/backend/organizations, but you can't PUT api.com/organizations, you have to PUT api.com/backend/organizations

If you are a "regular" user, you will be using api.com/organizations entry point, but if you are in the backend section of the app, you will need to use api.com/backend/organizations, since more operations are allowed.

So I can only think 2 approaches for now:

  1. I could duplicate the factories and have 2 Organizations factories, one pointing to api.com and the other pointing to api.com/backend, duplicating schemas, and everything.
  2. Replace synchronizer at "runtime". I'm not sure if this possible, but if I could swap between a one of the other synchronizer when requesting the factory (or similar) I think it could work.
  3. Another?

Hope the explanation is clear enough.

Thanks

Relationship's 'meta' object is not being added to request

Hi. I was trying to add a meta object into a relationship's object. For example, I have a user object which has many cars but I need to send some extra data about cars. So the request at the end should be like this:

{
  data: {
     attributes: {},
     id: '1',
     type: 'users',
     relationships: {
       'cars': [
          {
             id: '3',
             type: 'cars',
             meta: {
                wherever: 'happiness'
             }
          }
       ]
     }
  }
}

I tried to do:

//carElement has id:'3' and type:'cars'
carElement.form.meta = { wherever: 'happiness' };

user.form.link('cars', carElement);
user.save();

But I noticed when the request is sent, it doesn't send meta in any place.

How could I make this work?

Thanks in advance.

How to easily remove local store option

We are having some problems with the local storage cache mainly the size causing erratic behavior.

Can we easily set it not to use local store for our development phase..
I used this. But resource comes undefined.
//factory
var restSynchro = $jsonapi.sourceRest.create('Rest source', restUrl);
var synchronizer = $jsonapi.synchronizerSimple.create([ restSynchro]);

//controller
var resource = $jsonapi.getResource('test');

If I use the local store it works:
//factory
var localeSynchro = $jsonapi.sourceLocal.create('LocalStore synchronization', 'app');
var restSynchro = $jsonapi.sourceRest.create('Rest source', restUrl);
var synchronizer = $jsonapi.synchronizerSimple.create([localeSynchro, restSynchro]);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.