VueJS - trouble understanding .$set and .$add - json

I am trying to build an array of objects in VueJS and I am running into some issues with .$set and .$add.
For example, I need the following structure when adding new items/objects:
{
"attendees": {
"a32iaaidASDI": {
"name": "Jane Doe",
"userToken": "a32iaaidASDI",
"agencies": [
{
"name": "Foo Co"
}
]
}
}
}
New objects are added in response to an AJAX call that returns JSON formatted the same as above. Here is my Vue instance:
var vm = new Vue({
el: '#trainingContainer',
data: {
attending: false,
attendees: {}
},
methods: {
setParticipantAttending: function(data)
{
if (data.attending)
{
this.attendees.$add(data.userToken, data);
} else {
this.attendees.$delete(data.userToken);
}
}
}
});
This only works if I start with attendees: {} in my data but when I try attendees.length after adding an attendee, I receive undefined. If I use attendees: [], the new object does not appear to be added. And lastly, if I use .$set(data.userToken, data) it does not add in the 'token':{data..} format required.
What could be the issue here? What is the correct way to use $.add when starting with an empty array of objects?
UPDATE
I found that it works if I set attendees: {} and then, when adding a new object,
if (data.userToken in this.attendees) {
this.attendees.$set(data.userToken, data);
} else {
this.attendees.$add(data.userToken, data);
}
Not sure if there is a better way to accomplish this.

If you set attendees to an empty object ({}) it will not have a length attribute. That attribute is on Arrays.
If you set attendees to an empty array ([]) then you need to use $set (or really, I think you want .push()) – $add is intended for use on objects not on arrays.
I'm not quite following your last question – could you add more context?
EDIT 2:
The answer below was for Vue 1.x. For Vue 2.x and greater use:
this.$set(this.attendees, data.userToken, data);
More information here: https://v2.vuejs.org/v2/api/#Vue-set
EDIT:
Responding to your update, you should be able to just use $set in all cases. I.e. just do this:
this.attendees.$set(data.userToken, data);

As of version 0.6.0, this seems to be the correct way:
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
http://vuejs.org/guide/reactivity.html#Change_Detection_Caveats

Related

Is there a way of getting a cleaner JSON out of Couchdb?

I am wondering if there is a way to get a cleaner JSON with just the docs out of Couchdb instead of getting it under "rows" and then "doc"
This is the default output
{
"total_rows":1,
"offset":0,
"rows":[
{
"id":"7d9fd5824f9029186c1eec1bda005e75",
"key":"7d9fd5824f9029186c1eec1bda005e75",
"value":{
"rev":"1-f99879f67cfd27685f92c884c236a0fd"
},
"doc":{
"_id":"7d9fd5824f9029186c1eec1bda005e75",
"_rev":"1-f99879f67cfd27685f92c884c236a0fd",
"title":"Hello World",
"messeges":"This is the first messege. Helloo there"
}
}
]
}
This is the desired output:
{
"_id":"7d9fd5824f9029186c1eec1bda005e75",
"_rev":"1-f99879f67cfd27685f92c884c236a0fd",
"title":"Hello World",
"messeges":"This is the first messege. Helloo there"
}
Thanks
It would be useful to see your code. I suspect this is the output of the alldocs api? If you know the ID of the document you want you can use the get api which returns the JSON you want. Otherwise you must loop through the "rows" ie
for (x in results.rows) {...}
and then use x.doc to get your JSON.
Thanks all for the help.
I figured out a way doing it in Node js by using a map function attached to there query
in the nano page they listed it as
alice.list().then((body) => {
body.rows.forEach((doc) => {
console.log(doc);
});
});
instead I used it like this
alice.list().then((body) => {
var result = body.rows.map( (x) => {
return x.doc
});
console.log(result);
});
which works for me.
Still new till couchdb and databases in general.

Parsing JSON objects with arbitrary keys in Logstash

Consider a subset of a sample output from http://demo.nginx.com/status:
{
"timestamp": 1516053885198,
"server_zones": {
"hg.nginx.org": {
... // Data for "hg.nginx.org"
},
"trac.nginx.org": {
... // Data for "trac.nginx.org"
}
}
}
The keys "hg.nginx.org" and "track.nginx.org" are quite arbitrary, and I would like to parse them into something meaningful for Elasticsearch. In other words, each key under "server_zones" should be transformed into a separate event. Logstash should thus emit the following events:
[
{
"timestamp": 1516053885198,
"server_zone": "hg.nginx.org",
... // Data for "hg.nginx.org"
},
{
"timestamp": 1516053885198,
"server_zone": "trac.nginx.org",
... // Data for "trac.nginx.org"
}
]
What is the best way to go about doing this?
You can try using the ruby filter. Get the server zones and create a new object using the key value pairs you want to include. From the top of my head, something like below should work. Obviously you then need to map the object to your field in the index. Change the snipped based on your custom format i.e. build the array or object as you want.
filter {
ruby {
code => " time = event.get('timestamp')
myArr = []
event.to_hash.select {|k,v| ['server_zones'].include?(k)}.each do |key,value|
myCustomObject = {}
#map the key value pairs into myCustomObject
myCustomObject[timestamp] = time
myCustomObject[key] = value
myArr.push(myCustomObject) #you'd probably move this out based on nesting level
end
map['my_indexed_field'] = myArr
"
}
}
In the output section use rubydebug for error debugging
output {
stdout { codec => rubydebug }
}

EmberJS 2.7 How to restructure/reformat/customize data returned from the store

I have what I think is a very simple issue, but I just don't get how to do this data manipulation. This sadly didn't help, even though it's the same pain I am feeling with Ember.
Here is a route:
route/dashboard.js:
import Ember from 'ember';
export default Ember.Route.extend({
// this is for testing, normally we get the data from the store
model: function() {
return this.get('modelTestData');
},
modelTestData: [{
name: 'gear',
colorByPoint: true,
data: [
{y: 10, name: 'Test1'},
{y: 12, name: 'Test2'},
{y: 40, name: 'Test3'}
]
}],
});
The structure of the 'modelTestData' object has to be exactly like that as it is passed into a child component that needs it structured that way.
I can easily get my data from the API and put it into the model:
model: function() {
return this.store.get('category');
},
But then I need to restructure it...but how?
I have to somehow iterate over the categories collection and extract parts of data from each record to replace the 'data' part of the modelTestData object.
So I have 3 issues I am completely stumped on:
How to 'get at' the attributes I need from the model?
How to structure them as an array of objects with 'y' and 'name'?
How to assign that structure to the 'data' property of modelTestData instead of it being hardcoded?
Categories is a JSONAPI object like this:
{
"data":[
{
"id":"1",
"type":"categories",
"attributes":{
"name":"Carrying system",
"total-grams":"0.0"
}
},
{
"id":"2",
"type":"categories",
"attributes":{
"name":"Shelter system",
"total-grams":"0.0"
}
}
]
}
I need to map the grams value to 'y' and the name to 'name' in modelTestData.
Note that the category data is used in other routes for other purposes exactly as returned by the API. So I don't want to change the model structure itself, or what the API returns...that will break other parts of the app that do use 'category' in its original structure.
This is a specific use case that this route needs to massage the data to pass to the child component as per the structure of modelTestData.
I also wonder whether this data manipulation task belongs in a route?
Should I somehow do this in the serliazer adapter, creating a new structure as say 'categoryWeights' so I can then do:
model: function() {
return this.store.get('categoryWeights');
},
EDIT
I have managed to do this in the route, but it just gives me an array of objects. I need a single object containing 2 properties and an embedded array of objects.
model() {
return this.store.findAll('category')
.then(categories => categories.map(category => {
let data = {
y: category.get('totalGrams'),
name: category.get('name')
};
return data;
}))
},
This should probably go into a computed property:
dataForSubModel: Ember.computed('model.#each.totalGrams', 'model.#each.name', {
get() {
return [{name: 'gear', colorByPoint: true, this.get('model').map(m => ({y:m.get('totalGrams'), name:m.get('name')}))}
}
}),
The serializer is the wrong place, because its not that you need to convert it between the server and your app, but between your app and a strange component.
Actually the best thing would be to refactor the component.
Ok I got this to work in the route.
model() {
return this.store.findAll('category')
.then( function(categories) {
let data = [];
data = categories.map(category => {
return {
y: category.get('totalGrams'),
name: category.get('name')
}
});
return [{name: 'gear', colorByPoint: true, data}];
})
},
I still have the feeling this should be done in the adapter or serializer. Would be happy to see answers that show how to do that.

Should I convert JSON to Array to be able to iterate it with v-for?

In the following code I am getting data from server and filling array with them:
Vue.http.post('/dbdata', DataBody).then((response) => {
App.$refs.userContent.rasters_previews_list.$set(response); // putting JSON answer to Component data in userContent
console.log("App.$refs.userContent.rasters_previews_list: ", App.$refs.userContent.rasters_previews_list.length);
}, (response) => {
console.log("Error")
});
Now I am filling. data is declared in var userContent = Vue.extend({. I am using App.$refs.userContent.rasters_previews_list to set it's value, because one man from SO said that there is no other way to get access to constructor. I tried to do output of rasters_previews_list after changing with watch, but here is what I am see. http://img.ctrlv.in/img/16/08/04/57a326e39c1a4.png I really do not understand am I setting it's right way or no. If yes, why I do not see data and see only this crap?
data: function () {
return {
rasters_previews_list: []
}
}
But How I can iterate it with v-for?
<ul v-for="img in rasters_previews_list">
<li>{{img}}</li>
<ul>
This code is display one bullet. So it's look like it's assume that there is one object.
My object in browser console look like:
Object {request: Object, data: Array[10], status: 200, statusText: "OK", ok: true}
Your setting the full response instead of just the data you actually need.
Vue.http.post('/dbdata', DataBody).then((response) => {
App.$refs.userContent.rasters_previews_list.$set(response.data);
console.log("App.$refs.userContent.rasters_previews_list: ", App.$refs.userContent.rasters_previews_list.length);
}, (response) => {
console.log("Error")
});
If this isn't what you are looking for please post a full example.

How to avoid "Unable to get property 'X' of undefined or null reference" when creating $scope properties from JSON data

I want to populate some charting data from some JSON data pulled down using $http.get. However, the issue I have is the $scope property I am binding to doesn't exist until the JSON is returned, so the page is throwing an error when it loads.
How do I avoid the error? It feels like I have a chicken and egg scenario.
Example:
$scope.Model.Charts.Electricity = {
series: [
name: "2014 Target",
data: $scope.Model.Data.Json.Charts.Electricity.CurrentYearTarget
]
};
The Electricity.CurrentYearTarget property is the one that doesn't exist until the promise is completed:
promise.then(
function(payload) {
$scope.Model.Data.Json.Charts = payload.data;
});
The JSON is what then defines the objects that sit under .Charts. Example:
{"Electricity":
{"CurrentYearTarget":
[10000.0,
// snip
10000.0]
}
}
OK, so what can I do to work with this? I suppose I could wrap all of my properties like $scope.Model.Charts.Electricity and so forth into a simple JavaScript if statement, but that doesn't feel right.
I suggest you consider simplifying your approach somewhat, as $scope.Model.Data.Json.Charts.Electricity.CurrentYearTarget is somewhat verbose, and Model, Data, Json all mean the same thing really, you can probably cut some of these out.
However, this is beside the point, you can still acheive what you want to, just populate the data when the request has returned:
$scope.Model = { Data: { Json: { Charts: {} } } }
promise.then(
function(payload) {
$scope.Model.Data.Json.Charts = payload.data;
$scope.Model.Charts.Electricity = {
series: {
name: "2014 Target",
data: $scope.Model.Data.Json.Charts.Electricity.CurrentYearTarget
}
};
});