VasilioRuzanni / angular-modelizer

Simple and lightweight yet feature-rich models to use with AngularJS apps.
MIT License
26 stars 4 forks source link

JSON backslashes...not happy with 'Smart Table' plugin #8

Closed jackp55 closed 9 years ago

jackp55 commented 9 years ago

Hi Vasilio,

We're successfully using your modelizer...thx for that!.

I'm currently trying to get the 'Smart Table' plugin working ( http://lorenzofox3.github.io/smart-table-website/#examples-section ). It looks good, but the 'search filter' option is not working when i load models with 'modelizer' as i believe 'modelizer' is adding backslashes into JSON. If i load up server data with a regular $http call, JSON has no backslashes and 'Smart Table search filter' works.

ie: with $http.get

{"list":[{"reconciled":false,"currencyCode":"COP","receiptIds":[6958],"reconciliationId":195,"paymentTypeId":7,"paymentTypeEnglish":"Credit Card - MC","paymentTypeFrench":"Carte de crédit - MC","reconciliationStatusId":7517,"reconciliationStatusEnglish":"Submitted for Approval","reconciliationStatusFrench":"Soumis aux fins ...etc...

ie: with 'modelizer' .fetch {\"list\":[{\"approveOrReject\":\"\",\"reconciliationId\":195,\"reconciled\":false,\"currencyCode\":\"COP\",\"receiptIds\":[6958],\"paymentTypeId\":7,\"paymentTypeEnglish\":\"Credit Card - MC\",\"paymentTypeFrench\":\"Carte de crédit - MC\",\"reconciliationStatusId\":7517,\"reconciliationStatusEnglish\":\"Submitted for Approval\",\"reconciliationStatusFrench\":\"Soumis aux fins d'approbation\",\"userId\":1,\"cashierLogonId\

Can i set an 'options' flag somewhere for turning off escapes?

thx! JackP

VasilioRuzanni commented 9 years ago

@jackp55 Hi! Some kind of JSBin or Plunker would be very helpful but here are few questions to have a context:

Actually, there is nothing in Modelizer that encodes JSON in some particular way - everything is just delegated to Angular's $http (and angular.toJson() to parse some incoming JSON data). Seems like not a Modelizer issue at a glance but lets dig into it to make sure.

jackp55 commented 9 years ago

Hi there,

jackp55 commented 9 years ago

and, specifically it's the 'search' with 'Smart Table' that is not working with modelizer i believe...and i believe it's due to backslashes...

(the sort works nicely..but not the search)

http://lorenzofox3.github.io/smart-table-website/#section-filter

ie: it is causing this error for me:

RangeError: Maximum call stack size exceeded
    at comparator (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16803:29)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16864:14)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16838:42)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16838:42)
    at http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16829:14
    at Array.some (native)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16828:19)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16838:42)
    at deepCompare (http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16838:42)
    at http://nlem1wd0875w1.nhq.ci.gc.ca:8080/iprms-webpos-client/resources/angularJS/angular.js:16829:14
jackp55 commented 9 years ago
VasilioRuzanni commented 9 years ago

@jackp55 Thanks for the info! I'll definitely investigate that.

One more question, though - does SmartTable work with the data returned by raw $http.get()?

And one more thing. What it shows if you don't use the angular.toJson() when outputting the result?

JavaScript reconList.fetch().then( function (response) { $log.debug('Fetch success: response'); $log.debug(response); // <- no angular.toJson(...) call here

retModel = response; deferred.resolve(retModel); }

VasilioRuzanni commented 9 years ago

@jackp55 Btw, as a side note (not related to the backslashes issue), you mentioned you're using var reconList = ReconsForApprovalList.$new(); which is basically using a "single model" to fetch the collection.

Are you sure you don't want to have Recon model and use var reconList = Recon.$newCollection(); for this purpose for clarity? You might need to override collection's parse() method to extract the data from the list property` but that should work just fine, imo. Just curious.

jackp55 commented 9 years ago

thx for quick responses!

yeah, i'll refactor that single model vs. collection later... i believe it's unrelated...

jackp55 commented 9 years ago

Question: One more question, though - does SmartTable work with the data returned by raw $http.get()?
Answer: Yes, see below

Question: And one more thing. What it shows if you don't use the angular.toJson() when outputting the result? Answer: Yes, see below

VasilioRuzanni commented 9 years ago

@jackp55 Re: "modelize .fetch GET success: response, [object Object]"

Could you please output the response in a separate $log.debug(...) call? So that it outputs the object contents instead of [object Object].

P.S. Please also note that .fetch() method promise is resolved with the model instance. You can also try checking what Model.fetch({ rawData: true }) results with.

jackp55 commented 9 years ago

Hey there...sorry , a bit lost, i thought i did have a separate log statement...???

    this.loadReconsForApproval = function() {

        var reconList = ReconsForApprovalList.$new();

        var deferred = $q.defer();
        var retModel = undefined; 

        reconList.fetch().then(
                function(response) {
                    $log.debug ("modelize .fetch GET success: response, " + response);
                    $log.debug ("modelize .fetch GET success: angular.toJson(response), " + angular.toJson(response));
                    retModel = response;
                    deferred.resolve(retModel);
                },
                function(errResponse) {
                    $log.debug("Error on fetch recons for approval, error: " + angular.toJson(errResponse));
                    deferred.reject(errResponse);
                }
        );

        return deferred.promise;
    };

and... going to look at your Model.fetch({ rawData: true }) suggestion...

jackp55 commented 9 years ago

interesting... this is working better... should i always use the 'rawData:true' flag?

here are my modelize definitions...


    var reconForApprovalDef = modelize.defineModel("reconForApproval", {
        approveOrReject : '',
        reconciliationId: '',
    });

    var reconsForApprovalDef = modelize.defineModel("reconsForApprovalList", {
        urlPrefix: urlRoot + '/',
        baseUrl: '/reconciliation/submittedReconciliations',
        list: modelize.attr.collection({
            modelClass: 'reconForApproval'}),
    });

here is my Service.js code

        var reconList = ReconsForApprovalList.$new();

        var deferred = $q.defer();
        var retModel = undefined; 

        reconList.fetch({ rawData: true }).then(
                function(response) {
                    $log.debug ("modelize .fetch GET success: response with { rawData: true }, " + response);
                    $log.debug ("modelize .fetch GET success: angular.toJson(response) with { rawData: true }, " + angular.toJson(response));
                    retModel = response;
                    deferred.resolve(retModel);
                },
                function(errResponse) {
                    $log.debug("Error on fetch recons for approval, error: " + angular.toJson(errResponse));
                    deferred.reject(errResponse);
                }
        );

        return deferred.promise;

here are my log.debugs:

modelize .fetch GET success: response with { rawData: true }, [object Object]
modelize .fetch GET success: angular.toJson(response) with { rawData: true }, {"list":[{"reconciled":false,"currencyCode":"CAD","receiptIds":[14060],"reconciliationId":220,"paymentTypeId":3,"paymentTypeEnglish":"Credit Card - American Express","paymentTypeFrench":"Carte de crédit - American Exp",....etc
VasilioRuzanni commented 9 years ago

@jackp55 Nope, always using rawData: true option is not a recommended way (if overused, it defeats the whole purpose of using Modelizer, since you can make requests with plain $http in that case, while Modelizer is about maintaining model state on the client).

I'll see what might cause the issue - never encountered that myself, but want to investigate closely if thats a Modelizer issue or not.

P.S. A bit of offtopic but I see you use the $q.defer() in your code - which is totally unnecessary as .fetch() returns regular Promise on its own that you can chain .then() and .catch() to and return all that directly.

jackp55 commented 9 years ago

Ok thx, if i have time later today, i'll try to whip together a plunk for you.

but, i'm thinking it would be easy for you to plug in 'Smart Table' and try a 'filter/search' and see if it works...

http://lorenzofox3.github.io/smart-table-website/#section-filter

ie:

VasilioRuzanni commented 9 years ago

@jackp55 The plunkr will be highly appreciated. I'm not familiar with SmartTable and its ins/outs, so isolated Plunker illustrating the problem is going to be the best option. Thanks!

jackp55 commented 9 years ago

Here's a simpler example, (i'm not bothering doing a .fetch, as modelizer can't get out of plunker)

http://plnkr.co/edit/I0mctQIesZkqxSA8fmDR?p=preview

this example has a canned 'countryList', you'll see the backslashes, and you'll see that the 'global search' doesn't work

thx

jackp55 commented 9 years ago

Hey Visillio,

I was trying another 'table' solution (sorting, filtering, pagination) with modelizer and the same problem occurred. 'Range Error'

Please take a look at this plunker: http://plnkr.co/edit/UUzAyAFq1pzqh3OCl2FG?p=preview

this is using ngTasty solution (http://zizzamia.com/ng-tasty/directive/table/sorting).

so both Smart Table and ngTasty are throwing errors with modelizer (i believe due to backslashes) :(

it would be good to solve this...as angularjs tables are fairly important (to me and perhaps others...??)

thx

jackp55 commented 9 years ago

Hey Vasilio, any success yet?...sorry i mistyped your name!

thx jackp

VasilioRuzanni commented 9 years ago

@jackp55 Sorry, didn't have time for that at all - will look at it in the next few days

VasilioRuzanni commented 9 years ago

@jackp55 Well, I've found what might have caused the issue. Its not related to Modelizer itself, the difference between it and plain $http.get() was that the latter returns raw data while in case of Modelizer you try to use live (typed after your model class) objects array. This is why passing rawData: true option worked (it forced the method resolve the promise with the raw data).

Instead of passing rawData option around (which is designed for the extremely rare cases when you need to extend modelizer in a special way), you can just use .serialize() method (both Model and collection have it), so that instead of passing live models (with all the stuff and internal things, including circular references between model and collections), you just pass raw data to the Smart Table (it expects that).

Here is the Plunker demonstrating it: http://plnkr.co/edit/M2kEZ4B9BUjz0pBuNjhv?p=preview

Note, that I've also removed the redundant angular.toJson() call that caused the backslashes in the console - now you can see that there is a live array of objects, not a JSON string representing your data.

VasilioRuzanni commented 9 years ago

@jackp55 Btw, nice catch on Modelizer $request.get() - it is supposed to make an outside request if the baseUrl or url option value is an absolute URL and its probably a bug somewhere.

VasilioRuzanni commented 9 years ago

@jackp55 Please let me know if the comments above resolve issue or confirm its not related to Modelizer $request. Closing for now, feel free to reopen if you think there is an issue.

jackp55 commented 9 years ago

HI Vasilio,

So we are using the .serialize. Reading your code comments on 'serialize'... It seems to work for us, but are there any side affects? ie: does it screw up the models?

thx

VasilioRuzanni commented 9 years ago

@jackp55 There are no side effects of .serialize() - its just making Model instance a simple JavaScript object instead. From what I've seen, it seemed to me that SmartTable wants just data, not some model with methods or behavior - so you should be fine. The .serialize() doesn't mutate the model instance in anyway, just copies the data to a new object (including related/nested objects), so you can use the serialize() to feed to SmartTable and use model instance for server communication.