Difficulty Converting Array of Objects to Proper Type with Q.Promise and KO.mapping

I have encountered an issue while trying to filter an observable array. It seems that the ko.utils.arrayFilter method is converting all my model's field names to lowercase, causing unexpected behavior. I should mention that this project involves Typescript.

Here is a snippet of my Model:

    export class MyListModel {
    constructor(jsObject?: {}) {
        if (jsObject) {
            ko.mapping.fromJS(jsObject, {}, this);
        }
    }
    Text = ko.observable<string>();
    Value = ko.observable<string>();
}

Within my viewModel, I have defined the following field:

  inches = ko.observableArray<Models.MyListModel>([]);

At another part of the program, I utilize the filterInches() method to filter the array based on certain criteria. The 'value' parameter represents the currently selected value from a dropdown.

    filterInches(value) {

        if (value == 6) {
            var filtered = ko.utils.arrayFilter(this.inches(),
                function (item) {

                    if (parseInt(item.Text()) <= 8)
                        return true;
                });

            this.filteredInches(filtered);
        } else {
            this.filteredInches(this.inches());
        }
    }

While there are no compile errors, running the application in the browser triggers an error stating "item.Text is not a function". Upon inspection in Chrome, it appears that 'item' has been transformed into an anonymous object with fields being converted to lowercase. This transformation might be causing the issues I am facing. What could be the reason behind this change?

EDIT: Delving into a related section of the code, I suspect a potential explanation for its malfunction. It seems tied to the Q Promise library, although comprehending this library fully remains challenging (despite reading the documentation). I believe the developers who authored this code might have misconceptions about its functionality.

To verify any discrepancies, I attempted modifying the property names within our model:

    export class MyListModel {
constructor(jsObject?: {}) {
    if (jsObject) {
        ko.mapping.fromJS(jsObject, {}, this);
    }
}
  Cat = ko.observable<string>();
  Chicken = ko.observable<string>();
}

Upon revisiting the revised filterInches() method, it can be observed that 'item.Cat' functions during compilation, but 'Cat' is undefined when scrutinizing through Chrome's debugging tool. Surprisingly, the properties belonging to 'item' remain as 'text' and 'value':

    filterInches(value) {

    if (value == 6) {
        var filtered = ko.utils.arrayFilter(this.inches(),
            function (item) {

                if (parseInt(item.Cat()) <= 8)
                    return true;
            });

        this.filteredInches(filtered);
    } else {
        this.filteredInches(this.inches());
    }
}

This anomaly suggests that the JSON objects fetched are not properly mapped to instances of MyListModel. Nevertheless, I presume the issue does not lie within the MyListModel itself.

The disruption seemingly emerges from the segment responsible for obtaining the 'inches' initially:

    refreshInches() {
        this.DataService.getInches().done(entities => {
            this.inches(entities);
        });
    }

Subsequently, the getInches() method presents itself as:

    getInches(): Q.Promise<Array<Models.MyListModel>> {
        return Q($.getJSON(this._baseUrl + 'GetInches'));
    }

It seems like the original intention was to retrieve inch-related data asynchronously from an endpoint and convert the JSON information into MyListModel objects. Frankly, I lack sufficient knowledge regarding Q.Promise to pinpoint probable flaws within the getInches() routine. Nonetheless, it's discernible that the method currently returns an array populated by unnamed objects sourced from JSON data.

To offer context, the JSON payloads acquired from the endpoint adhere to this structure:

[{"text":"0","value":"0"},{"text":"1","value":"1"},...]

Can someone provide insights on enhancing the getInches() method to align with its intended functionality?

Answer №1

Based on the code provided, the function getInches should return a

Q.Promise<Array<Models.MyListModel>>
, which means it should be a promise for an array of MyListModel objects.

However, the current implementation does not match this expectation:

getInches(): Q.Promise<Array<Models.MyListModel>> {
    return Q($.getJSON(this._baseUrl + 'GetInches'));
}

Instead of returning the expected type, the above snippet returns a promise for

<whatever the server gives you>
, which seems to be an array of plain objects in this case.

To align it with the intended type, we could modify it as follows:

getInches(): Q.Promise<Array<Models.MyListModel>> {
    var jqXhr = $.getJSON(this._baseUrl + 'GetInches');

    return Q(jqXhr).then(data => {
        return data.map(item => {
            return new Models.MyListModel(item);
        });
    });

    // or, alternatively
    return Q(jqXhr).then(data => data.map(item => new Models.MyListModel(item)));
}

After making these changes, we can save the newly created MyListModel instances in an observable:

refreshInches() {
    this.DataService.getInches().done(this.inches);
}

It's worth noting that this.inches is an observable, and observables are functions, allowing us to use them directly as callbacks.

A promise handler function receives the promised value as its first argument. Observables store the value passed to them as arguments, making them a suitable choice here.


In addition, your approach to filteredInches appears overly complex. Instead of defining it as a standalone function, consider making it a computed property that depends on an observable in your viewmodel. This ensures consistency throughout.

this.filteredInches = ko.pureComputed(() => {
    var value = this.value();

    return ko.utils.arrayFilter(this.inches(), item => {
        return value != 6 || +item.Text() <= 8;
    });
});

Upon reviewing your viewmodel setup, it may be beneficial to have a numeric observable (or computed) available to avoid manual type conversion when utilizing the Text property in calculations.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular ng-repeat not populating the list properly, causing a collapse not to display

Currently, I am working on developing an app using Angular.js and Bootstrap UI, but I have run into a problem with a collapse navigation feature. The issue I am facing is that I have an ng-repeat that should be functioning properly. However, when I click ...

Accessing values from an array within a JSON object using jqGrid

Here is an example of my JSON data: [{"codDiretor":"123", "nomeDiretor":"Nome do Diretor", "data":"29/01/2014", "documentos":[{"codDocumento":"1", "nomeDocumento":"Primeiro Doc"}, {"codDocumento":"2","nomeDocumento":"Segundo Doc"}] ...

Is it considered a best practice to utilize JavaScript for positioning elements on a

I recently started learning JavaScript and jQuery, and I've been using them to position elements on my website based on screen and window size. It's been really helpful, but I'm starting to wonder if it's a good practice since it makes ...

Modifying tooltip format in React ApexChart from dots to commas

I am in the process of creating an app targeted towards German users, who traditionally use commas (20,00) instead of dots (20.00) for numbers. I am using react-apexcharts and struggling to figure out how to replace the dots with commas in both my chart an ...

What potential factors could lead to an MUI Snackbar failing to produce the accurate class names?

I am facing an issue with displaying notifications on my Gatsby blog whenever the service worker updates. I am using a MUI Snackbar toast for this purpose. However, sometimes the styling of the toast is not applied correctly and it ends up looking like thi ...

Angular FormData fails to append and upload files

I am attempting to use FormData in order to upload a file through an HTTP Request. Here is the HTML code: <ng-template #displayApp> <div class="display flex justify-content-center"> <div > <p-fileUploa ...

Steps for traversing through nested elements

Here is the HTML code snippet I am currently working with: <div class="date"> <h3 class="date-title">Today</h3> <div class="film"> <img class="poster" src="film1" /> <h4 class="title">Film 1</h4> ...

NextAuth.js in conjunction with nextjs version 13 presents a unique challenge involving a custom login page redirection loop when using Middleware - specifically a

I am encountering an issue with NextAuth.js in Nextjs version 13 while utilizing a custom login page. Each time I attempt to access /auth/signin, it first redirects to /login, and then loops back to /auth/signin, resulting in a redirection loop. This probl ...

looping through the iteration

Here is a link to my original plunker demonstration: http://plnkr.co/edit/9UBZ9E4uxAo1TXXghm1T?p=preview. In the case of div 4 (ng-if="show==4"), I am looking for a way to hide the particular div when the list is empty. Currently, each div is displayed fo ...

Is there a way to individually apply loading to only the button that has been clicked in vuejs?

One problem I am facing is that when I click a specific button in a table, all buttons end up in loading mode. The table loops and displays data from an API, with a button embedded in each row. Upon clicking the button, it should send the ID of the clicked ...

Work with Dart Language to Parse a Nested JSON Array and Store it in a Model Class

In regards to my inquiry here I am seeking a solution to extract and parse a JSON array without a key nested within another JSON array, and then store it in a Model class. Below is the JSON Array that requires parsing: [ { "pk": 100, ...

Union does not contain the specified property in Typescript

Here are the types that I have: Foo { foobar: any } Bar { fooBarBar: any; } I want to use a function defined like this: this.api.submit(param: Foo | Bar) When trying to use it, I encountered an issue: this.api.submit(param.foobar) // does no ...

The 'v-model' directive necessitates a valid attribute value for the left-hand side (LHS)

I am facing an issue with my Vue application. I have a table where each row has its own unique id. I need to show or hide certain elements based on a condition in the v-model directive which compares the row id with a value in the model. The current code s ...

Enhancing transparency with a touch of background color

After successfully exporting my chart created in canvas as an image file, I noticed that the image turned out to be transparent without any background. Is there a way through code to add a background color to this existing image obtained from canvas? For ...

Is it possible to add an element to an array every time a particular function is executed?

Implementing infinite scroll involves using an array called hotels that receives data from the $http.get() method. Now, the goal is to populate a new array named hotelsNew[] with the values from the hotels array, while incrementing the values of m and j. ...

Using JavaScript to transform base64 encoded strings into images

I'm currently working on an app using Titanium and I have a base64 string that I need to convert into an image from JSON data. Any assistance you can provide would be much appreciated. Thank you! ...

Retrieve information in JSON format from a document

I'm trying to extract data from a JSON file without knowing the exact location of the data. Here is an example JSON: var names= [ { "category":"category1" , "name1":"david", "name2":"jhon", "name3":"peter" }, { "category":"catego ...

It appears that the NodeJs Express 4 async function in the model is returning before completion

I'm currently working on organizing my project by splitting the logic into different folders such as routes, views, models, and controllers. Within a model named data (models/datamodel.js), I have implemented two methods to retrieve data for populati ...

Swap out the image backdrop by utilizing the forward and backward buttons

I am currently working on developing a Character Selection feature for Airconsole. I had the idea of implementing this using a Jquery method similar to a Gallery. In order to achieve this, I require a previous button, a next button, and the character disp ...

Having trouble storing data in a MYSQL database with NodeJS and ReactJS

When trying to submit the form, a "Query Error" popup appears and data is not being saved in the database. API router.post("/add_customer", (req, res) => { const sql = `INSERT INTO customer (name, mobile, email, address, state, city, policytype, insu ...