Home > OS >  nested v-for loop not rendering
nested v-for loop not rendering

Time:11-01

I am trying to display a table full of Orders and the corresponding Order details in a row-like fashion. However, I've run into a bit of a conundrum. Any geniuses out there? I've tried all sorts of variations in approaching this problem but I'm stuck. Someone mentioned that perhaps using a 'computed' property would do the trick but I haven't been able to get it to work >=/. A bit of help, maybe a lot of help, would be greatly appreciated!

<div id="MyOrdersApp" >
    <table >
        <thead>
            <tr style="color:black;font-size:2em;">
                <th style="text-align:center;">Order Id</th>
                <th style="text-align:center;">ProductIdsAndQuantity</th>
                <th style="text-align:center;">Total Cost</th>
                <th style="text-align:center;">Order Status</th>
                <th style="text-align:center;">Shipment Tracking URL</th>
                <th style="text-align:center;">Created Date</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" >
                <td>{{order.OrderId}}</td>
                <td>
                    <ul>
                        <li v-if="order.CartLineItems != null" v-for="item in order.CartLineItems;" :key="uniqueKey">
                            <img :src="item.ProductImageUrl" />
                            <span>{{item.ProductName}} &nbsp;|&nbsp;</span>
                            <span>Quantity: {{item.Quantity}} &nbsp;|&nbsp;</span>
                        </li>
                    </ul>
                </td>
                <td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
                <td>{{order.OrderStatus}}</td>
                <td>{{order.ShipmentTrackingURL}}</td>
                <td>{{order.CreatedDate | formatDate }}</td>
            </tr>
        </tbody>
    </table>
</div>
<script>
        var MyOrdersApp = new Vue({
            el: '#MyOrdersApp',
            data: {
                parsedOrders: [],
                theOrders: [],
                uniqueKey: 0
            },
            computed: {
                cartLineItems: function () {
                    return this.parsedOrders[0].CartLineItems;
                }
            },
            methods: {
                getMyOrders: function () {
                    var scope = this;
                    this.$http.get("https://"   location.host   "/Home/GetMyOrders").then(resp => {
                        if (resp.status == 200) {
                            this.theOrders = resp.body;
                            scope.setCartLineItems();
                        }
                    });
                },
                setCartLineItems: function () {
                    var scope = this;
                    var cartLineItems = [];
                    var cartDict = {};

                    for (var i = 0; i < this.theOrders.length; i  ) {
                        cartDict = {};
                        cartLineItems = [];

                        cartDict = JSON.parse(this.theOrders[i].ProductIdsAndQuantity).CartLineItems;

                        for (var key in cartDict) {
                            var lineItem = JSON.parse(cartDict[key]);
                            cartLineItems.push(lineItem);
                        }
                        //this.allorders[i].CartLineItems = cartLineItems;
                        //scope.$set(this.allorders[i], 'CartLineItems', cartLineItems);
                        //this.theOrders[i].CartLineItems = cartLineItems;
                        scope.$set(this.theOrders[i], 'CartLineItems', cartLineItems);
                    }

                    this.parsedOrders = this.theOrders;

                    console.log("~~ Parsed Cart! ~~ ");
                    console.log(this.parsedOrders);
                    console.log(this.parsedOrders[1].CartLineItems);
                }
            },
            mounted: function () {
                var scope = this;
                this.getMyOrders();
                setTimeout(x => { scope.$forceUpdate(); scope.uniqueKey  ; }, 1000);
            }
        });
</script>

How should I modify this to properly display the values in 'CartLineItems'??

Btw, parsedOrders looks like this:

parsedOrders

parsedOrders_2

If I comment out the inner v-for, the other columns display just fine and the table looks like this:

the table with the inner v-for commented out

Some more background... when I fetch the orders via the $http call and the server returns the array of JSON, the ProductIdsAndQuantity property needs to be parsed as a JSON object and then set as it's own property on the order in question. The tricky part here is that the Vue component seems to not be reacting to the change in the order object array data. Hence, the need for a parsedOrders property and/or the use of scope.$forceUpdate(); or scope.uniqueKey ;. These were proposed solutions to the issue of the Vue component not re-rendering. However, these solutions are not working. So I'm stuck scratching my head...

CodePudding user response:

You can't have both v-for and v-if on the same statement that's what is causing the issue. So instead try using computed in this case

<tbody>
            <tr v-for="(order, i) in parsedOrders" style="background-color:snow;text-align:center;" >
                <td>{{order.OrderId}}</td>
                <td>
                    <ul>
                        <li v-for="(item, index) in getCartLineItems(order)" :key="index">
                            <img :src="item.ProductImageUrl" />
                            <span>{{item.ProductName}} &nbsp;|&nbsp;</span>
                            <span>Quantity: {{item.Quantity}} &nbsp;|&nbsp;</span>
                        </li>
                    </ul>
                </td>
                <td style="color:black;font-size:1.5em;font-weight:bold;">{{order.TotalRevenue | currency }}</td>
                <td>{{order.OrderStatus}}</td>
                <td>{{order.ShipmentTrackingURL}}</td>
                <td>{{order.CreatedDate | formatDate }}</td>
            </tr>
        </tbody>

and in computed

computed: {
  getCartLineItems() {
   return order => {
    if(order?.CartLineItems && order.CartLineItems.length) return order.CartLineItems;
    return [];
   }
 }
}
  • Related