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

Terminate the loop in a bash script if a certain condition is met

I have a set of numbers (1 2 3 4 5) magicnumber=7 If the magic number equals any number in the set or is greater than the highest number in the set, then do the following: {array[@]} - contains numbers highnum=determine the highest number in the set f ...

Unable to modify existing attributes in a sails.js model

I'm new to sails.js and I have a question about adding fields to an existing model in Sails.js. Here is the current model: module.exports = { attributes: { id: { columnName: 'id', type: 'integer&apos ...

Retrieving the 'red' pixel data from the texture rendered with gl.texImage2D

My objective is to transfer a Float32array to my fragment shader using a texture in order to process the data within the shader and then send it back to JavaScript. Since the data is not in the form of an image, I opted to transmit it as 'gl.R32F&apos ...

Can a variable be declared within the path references of the Firebase database?

In an effort to update my app's database references, I am working on implementing specific Firebase rules that involve adding buildings and depts nodes inside the user node. This decision was prompted by a discussion on best practices for writing Fire ...

Struggling with implementing jquery Ajax and a php script to fetch information from a mysql database

I'm encountering issues with my current web app project in displaying a simple jpg image based on the selected radio button using jQuery AJAX along with a PHP script to interact with MySQL. Below is my ajax.js file: $('#selection').change( ...

Deleting JSON files using Discord and Node.js by requiring them from a specific folder

Currently, I am in the process of developing a Discord bot using Node.js. One of the functions within the bot utilizes JSON files to store information about specific entities. I aim to create a command in Discord that, when called with a specific name asso ...

What is the best way to display a Base64 image in a server-side DataTable?

This HTML code is designed to load server-side data into a table. The data is retrieved from the controller using AJAX requests. <script type="text/template" id="tablescript"> <td><%=Name%></td> <td><%=PhoneNumber%> ...

Unintentional GET request triggered by Axios baseURL

I have encountered a strange issue where defining axios.defaults.baseURL = baseUrl; results in an unexpected GET request right after initializing my Vue app. Any assistance would be greatly appreciated! Below are images showing the code and network reques ...

The steps for removing a Laravel session array

Greetings! I am currently working on a functionality to remove a product array from the cart session when the quantity is 1. If the user attempts to remove it at this point, it will simply unset that particular item. Below is an excerpt of my code: public ...

Angular.js and D3 - The Perfect Combination for Dynamic Data Visualization!

Having some trouble creating a chart with angular.js. The chart is not appearing on the page when using rout.js, but it works fine without it. Here's my code: var myapp = angular.module('myapp', ['angularCharts']); function D3 ...

Problems with installing ambient typings

I'm having trouble installing some ambient typings on my machine. After upgrading node, it seems like the typings are no longer being found in the dt location. Here is the error message I am encountering: ~/w/r/c/src (master ⚡☡) typings search mo ...

Retrieving JSON data from $routeParams in AngularJS

Currently, I am working on a controller that is responsible for saving address data and changing the location to the next page with the JSON response as a parameter. Here's the code snippet that handles this: $routeProvider.when('/checkout/:chec ...

Why does the text in a div display in Safari 8.2 and Chrome 39, but not in Firefox 34?

In my HTML document, I have a div tag located within the body like so: <div id="content_text"></div>​ Using javascript, I later set the contents of the div like this: var content_text = document.getElementById("content_text") c ...

Boost Google Pagespeed score by reducing 'Total Blocking Time' in NextJs

I've recently started using NextJS and I'm looking to improve my Google Pagespeed ranking. So far, I've made some good progress in optimizing different metrics. From the screenshot provided, it's clear that the only issue remaining i ...

Error: Cannot access 'addEventListener' property of null in Chrome Extension due to TypeError

I've been working on developing a chrome extension that autofills input forms in web pages. However, I encountered an error that says "cannot read properties of null." This issue arises when I try to add an event listener to a button in my code. The f ...

The transparency level of materials in THREE.js

When using the lambert shader, I encountered an issue with setting the material. In the example provided, it sets the material as follows: this.material.uniforms.emissive.value = new THREE.Color( Math.random(), Math.random(), Math.random()); Prior ...

Unexpectedly, the child component within the modal in React Native has been resetting to its default state

In my setup, there is a parent component called LeagueSelect and a child component known as TeamSelect. LeagueSelect functions as a React Native modal that can be adjusted accordingly. An interesting observation I've made is that when I open the Lea ...

Encountering issues with utilizing global variables in Ionic 3

Using Ionic 3, I created a class for global variables but encountered an error Uncaught (in promise): Error: No provider for Globals! Error: No provider for Globals! at injectionError (http://localhost:8100/build/vendor.js:1590:86) at noProviderError Th ...

Just starting out with TypeScript and running into the error: "Cannot assign type 'null' to type 'User[]'"

Why is TypeScript giving me an error message here? const dispatch = useAppDispatch(); useEffect(() => { onAuthStateChanged(auth, (user) => { dispatch(getUser(user)); }); }, [dispatch]); Error: Argument of type 'User | nul ...

I encountered an issue stating, "The function `req.redirect` is not recognized."

Recently starting out with node development. Encountering the error below: TypeError: req.redirect is not a function at Post.create (/var/www/html/node_blog/index.js:40:7) at /var/www/html/node_blog/node_modules/mongoose/lib/utils.js:276:16 a ...