VueJS, loading attribute dynamic with json object - json

I have a problem on my last Vue JS page. I think I am totally wrong.
Let me explain, I have a button which make an API GET call to the backend and I got an array as a response from the API.
When I received this array, I push data in this.templates.
I have a v-for on this array :
<v-flex
class="pl-5"
xs12
md4
v-for="item of templates"
:key="item._id"
>
with inside :
<v-card elevation="10" :loading="loadingTemplates[item._id]">
When I received the response, v-card are correctly displayed with loading true. After this, I have a second POST request for each element, and when I received the response, I set to false the value :
console.log(`Response for ${element._id} and ${element.loading}`);
this.loadingTemplates[element._id] = false;
Log is OK, i have ID and true value.
I set false, but loading is still displayed....
Why ?
Maybe I need to use json object for templates, but i don't know how.
TO resume :
GET Request ==> Get Array with x jobs
POST Request for x jobs ==> With v-simple-table displayed.

As #stellr42 mentioned in his comment, Vue 2 has some limitations on reactivity when it comes to arrays. You can have a look into this official documentation.
Vue cannot detect the following changes to an array :
When you directly set an item with the index, e.g. this.loadingTemplates[element._id] = false
When you modify the length of the array, e.g. this.loadingTemplates.length = newLength
Demo as per the above statements :
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
loadingTemplates: [true, true, false, true]
},
mounted() {
this.loadingTemplates[1] = false; // Not updating
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item_id in [0, 1, 2, 3]">{{ loadingTemplates[item_id] }}</li>
</ul>
</div>
Hence, To update and make it reactive - You also have to trigger state updates in the reactivity system.
Working Demo :
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
loadingTemplates: [true, true, false, true]
},
mounted() {
this.$set(this.loadingTemplates, 1, false);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item_id in [0, 1, 2, 3]">{{ loadingTemplates[item_id] }}</li>
</ul>
</div>

Related

Unit test a V-If with Jest

How do I test the following v-if on my parent component using Jest?
Parent:
<div class="systemIsUp" v-if="systemStatus == true">
foo
</div>
<div class="systemIsDown" v-else>
bar
</div>
<script>
export default {
name: 'File Name',
data () {
return {
systemStatus: null,
}
},
</script>
Here is my current setup for testing if those divs render when I change the value of the systemStatus variable
Unit Test:
import { shallowMount } from '#vue/test-utils'
import FileName from 'path'
describe('FileName', () => {
//Declare wrapper for this scope
const wrapper = shallowMount(FileName)
it('Should display message saying that the system is down if "systemStatus" data variable is false', () => {
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false})
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
});
});
I have tried using contains and toContain instead of includes but still cannot get it to work, Jest returns the following:
expect(received).toBe(expected) // Object.is equality
Expected: true
Received: false
expect(wrapper.html().includes('.systemIsDown')).toBe(false)
wrapper.setData({ systemStatus: false })
expect(wrapper.html().includes('.systemIsDown')).toBe(true)
^
Clearly it cannot see the systemIsDown div at all and does not think it exists hence why the first expect passes but how can I get it to see the div when the systemStatus variable is updated?
Thanks
Changed around the assertion to look for specific CSS selector as follows:
wrapper.setData({ systemStatus: false})
expect(wrapper.find(".systemIsDown")).toBeTruthy()
This should work, if you want to check given DOM element has been created (or not):
expect(wrapper.find(".systemIsDown").exists()).toBe(true) // or false
more here

Vue-if conditional not working. if-Else block appears to be skipped

This is a follow up question to one I posted here: (I have 2 records in a database Vue outputs 8 records). In that question, was having trouble fetching a JSON list of games for an online casino I'm building. In my original question, Vue was unable to load the JSON as JSON, but now that's fixed.
I am now trying to parse this JSON using Vue to loop through all of the games in the games array and print either In progress or Game is joinable. However, instead of getting 8 different records from the database (from a weird response array object returned by this.$http.get. I now see that my JSON list is seemly being ignored by my Vue template; none of the objects in the collection get outputted (again either In progress or Joinable. I just get a blank list.
Is my v-if conditional programmed correctly? I checked the documentation and everything seems to be set up correctly. I find it odd that neither the v-if, or v-else, divs> are executed.
vuewgames.blade.php
#extends('app')
#section('content')
<strong>Below is a list of joinable games</strong>
<div class="container">
<games></games>
</div>
<div id="games-list">
<template id="games-template">
<ul class="list-group">
<li class="list-group-item" v-for="game in games">
<strong>play against #{{ game.player1 }}</strong>
</li>
</ul>
<pre>#{{ games | json }}</pre>
</template>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.0.3/vue-resource.js"></script>
<script src="js/all.js"></script>
#endsection
all.js
Vue.component('games', {
template: '#games-template',
data: function() {
return {
games: []
};
},
created: function () {
var self = this;
this.$http.get('/api/games').then(function (response) {
// fetch array from jsoN object
response.json().then(function (games) {
console.log(games);
});
});
},
});
new Vue({
el: 'body'
});
The reason that you're not getting the information to the instance is due to scope.
When you're using closures in javascript the scope of the this isn't the containing object.
One way to get around this is to assign this to another variable outside of the function and then use that instead. You should be able to get it working by changing your created method to be:
created: function () {
var self = this;
this.$http.get('/api/games').then(function (response) {
// fetch array from jsoN object
response.json().then(function (games) {
self.games = games;
});
});
},
Hope this helps!

WinJS Need help binding json response to listview

I have been messing with the code trying to get json to bind with winJS listview.
At the moment I an getting an error Exception: Cannot use 'in' operator to search for '0' in [{"$id":"1","Distance":0.083516275210499508,"Jo............
Need some help, thanks
WinJS.xhr({
url: "http://api.secondyearvisajob.com.au/api/jobs/GetNearActiveJobs",
type: "POST",
responseType: "",
data: JSON.stringify({ LocationId: 23555, kms: 10 }),
headers: { "content-type": "application/json" }
}).done(
function completed(request) {
alert(request) //[object: Object]
alert(JSON.stringify(request.response)) // my data
alert(JSON.parse(request.response)) //[object: Object],[object: Object]
alert(request.statusText)
WinJS.Namespace.define("Sample.ListView", { data: new WinJS.Binding.List(request.response) });
},
function error(request) {
alert(request)
}
);
WinJS.UI.processAll()
<div class="smallListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
<div class="smallListIconTextItem">
<div class="smallListIconTextItem-Detail">
<h4 data-win-bind="textContent: Distance"></h4>
</div>
</div>
</div>
<div id="listView"
class="win-selectionstylefilled"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource: itemDataSource :Sample.ListView.data.dataSource,
itemTemplate: select('.smallListIconTextTemplate'),
selectionMode: 'none',
tapBehavior: 'none',
layout: { type: WinJS.UI.ListLayout }
}">
</div>
There are a couple things happening here in your code.
First of all, request.response from your REST call is a JSON string, not an array as is required to initialize a new WinJS.Binding.List. The exception you're seeing is coming from passing a string. So you need to use JSON.parse(request.response) to get that array:
var arr = JSON.parse(request.response);
var list = new WinJS.Binding.List(arr);
Next, because WinJS.xhr is an asynchronous API, what's probably true is that WinJS.UI.processAll is attempting to initialize the ListView before you have the response and before you've even defined the Sample.ListView namespace. To correct this, omit the itemDataSource property from the HTML, and set that property directly in code. That is, continuing from the above:
var listview = document.getElementById("listView");
listview.winControl.itemDataSource = list.dataSource;
And the data-win-options attribute in HTML looks like this:
data-win-options="{
itemTemplate: select('.smallListIconTextTemplate'),
selectionMode: 'none',
tapBehavior: 'none',
layout: { type: WinJS.UI.ListLayout }
}"
That should help you move forward.
P.S. Just a suggestion, when posting questions about exceptions it's always helpful to identify exactly where in the code the exception is raised. That'll get you faster and better responses, as otherwise I had to put your code into a project to find that information.

Load data from bd in senchaTouch app using webservice who return a json

I try to display some data in my Sencha touch application, but it doesn't work... and i can't find what I'm doing wrong.
My webSiste return a json object who look like this
[{"name":"a","id":1}]
the script is getting the Json and display it:
Ext.regApplication({ name: 'Command',
phoneStartupScreen: 'phone-startup.png',
phoneIcon: 'apple-touch-icon.png',
launch: function(){
this.viewport = new Ext.Panel(
{
layout: 'fit',
fullscreen: true,
items: [{xtype: 'list',
itemTpl: new Ext.XTemplate('<div>{name}</div>'),
store: stores
}],
dockedItems: [{xtype: "toolbar",
dock: "top",
title: 'MovieCommand',
items: [{ui: 'back',text: 'back',handler: function(){}}]
}]
});
}
});
Ext.regModel('Commands', {
fields: ['name', 'id' ]
});
var stores = new Ext.data.Store(
{model: 'Commands',
proxy: {type: 'scripttag',
url: 'http://localhost:8080/GTI710/commandes/liste.htm',
format: 'sencha',
reader: new Ext.data.JsonReader ({
type: 'json',
})
},
});
stores.load();
I don't have any error in the java script but nothing is displayed.
I just want to have the "a" displayed but it doesn't work, I don't know why...
The ScriptTagProxy, which you are using, requires a response from server that's composed of legitimate Javascript code.
Specifically, the code is a callback function with the desired JSON data you what as the its first argument:
someCallback([{"name":"a","id":1}]);
The name of someCallback is generated dynamically by Sencha Touch when the request is sent. In other words, your attempt to store the response with a static file will not work.
The name of someCallback is passed as a parameter in the GET request sent by Sencha Touch, the key of which defaults to callback.
If you don't want to have a web server as the data source, checkout Ext.util.JSONP.

Why is my dijit.Tree not populated from json source?

I am new to dojo and spring development. I am trying to populate a Tree widget using a json response from a spring-mvc controller. I'm following the examples from the dojocampus website quite closely.
Firstly if I use a local data source it works ok:
<script type="text/javascript">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
dojo.addOnLoad(function() {
var rawdata = [{"rid":"b1c","name":"Test Parent","children":[{"rid":"1c4","name":"Test Child 1","children":[]},{"rid":"ee6","name":"Test Child 2","children":[]}]}];
var store = new dojo.data.ItemFileReadStore({
data: {
identifier: 'rid',
label: 'name',
items: rawdata
}
});
var treeModel = new dijit.tree.TreeStoreModel({
store: store,
query: {name: 'Test Parent'},
childrenAttrs: ["children"]
});
new dijit.Tree({
model: treeModel
},
"treeOne");
});
</script>
<div id="treeOne">
</div>
But if I use my json url the tree doesn't appear:
<script type="text/javascript">
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
dojo.addOnLoad(function() {
var store = new dojo.data.ItemFileReadStore({
url: "/Demo2/glossaryobjects/categories.json"
});
var treeModel = new dijit.tree.TreeStoreModel({
store: store,
query: {name: 'Test Parent'},
childrenAttrs: ["children"]
});
new dijit.Tree({
model: treeModel
},
"treeOne");
});
</script>
<div id="treeOne">
</div>
When I debug with Firebug I can see that the json response appears to be loaded correctly. It looks like this:
{"identifier":"rid","items":{"rid":"b1c","name":"Test Parent",
"children":[{"rid":"1c4","name":"Test Child 1","children":[]},
{"rid":"ee6","name":"Test Child 2","children":[]}]}, "label":"name"}
There is an error in Firebug:
"dijit.tree.TreeStoreModel: query {"name":"Test Parent"} returned 0 items, but must return exactly one item"
It looks like the ItemFileReadStore is not correctly loaded. Anyone know what I'm doing wrong? I've been tearing my hair out for days trying to get this to work, so any help is much appreciated.
Cheers,
Rod.
OK! Problem solved (for me):
If you have a close look at the store produced by each, the data is there for both, but the way the store represents each is different.
With the url JSON data, you get
_arrayofallitems []
_arrayoftoplevelitems Object {....
id...
items...
etc.
with the string data, you get
_arrayofallitems [] 62 items
_arrayoftoplevelitems
[0]
id
items
etc.
If you intercept the JSON response from xhrGet, and compare it to the string, you'll see that the JSON response is not an array (no []) whereas the string is.
Solution: declare an empty array, push the JSON response into it,
then pass the array to ItemFileReadStore:
dojo.xhrGet( {
url: 'test.php',
handleAs: "json",
preventCache: 'true',
load: function(response, ioArgs){
var rawdata = [];
rawdata.push(response);
var store = new dojo.data.ItemFileReadStore({ data: {
identifier: "id",
label: "label",
items: rawdata }
});
loadtree(store);
}});
It worked for me (finished an afternoon of frustration)...
The error you mentioned:
"dijit.tree.TreeStoreModel: query {"name":"Test Parent"} returned 0 items, but must return exactly one item"
Should be from using a TreeStoreModel instead of a ForestStoreModel. The former requires only one item be returned for the root node. Your fix probably worked because you shoved it into a single array.
Take a look at:
http://ofps.oreilly.com/titles/9780596516482/application_widgets.html