I need to reverse the order of a JSON feed that is being used within a Vue.JS project.
In other frameworks the reverse() function has done the job. I have tried adding to the Vue.JS script but no joy yet.
Any ideas on other syntax I could try?
<script type="text/javascript">
new Vue({
el: '#vueapp',
data: {
json: null
},
created: function () {
var _this = this;
$.getJSON('https://www.example.com/myfeed.json', function (json) {
_this.json.reverse() = json;
});
}
});
</script>
So the last item in the JSON (the house on the side of the mountain in the example below), will display first when the page loads the JSON data.
https://jsfiddle.net/5kt9jurc/3/
Some Googling seems to show reverse() no longer works with Vue2 and is deprecated.
You can reverse an array. Take a look at my fiddle. I replaced getJSON with fetch to use promises. Also you don't need to do var _this = this;
It looks a bit weird. Since in Vue.js properties are reactive you can just set a value.
Here is a code:
const app = new Vue({
el: '#app',
data: {
items: []
},
created: function() {
fetch('https://api.jsonbin.io/b/5b02b2bbc83f6d4cc7349a7b')
.then(resp => resp.json())
.then(items => {
this.items = items.reverse()
})
}
});
I think what you want is something like this:
_this.json = json.reverse();
That is, assuming json is an already parsed json array. Otherwise, first parse the json string:
const array = JSON.parse(jsonString);
this.data = array.reverse();
The way you are doing you are trying to assign a value to the result of an expression, which doesn't make much sense (right side values can't be assigned to).
Related
I'm new to vue.js but I'm trying to display a list of options from an underlying array. However, when the underlying array is changed the list does not update/re-render. I am assigning the new array directly to the vue instance data value (not using splice or assigning via index) and in the console if I try and print out the underlying data (vm.clarifyings) that is updated, it is just the re-rendering that is not working. Even using vm.clarifyings.push(object) does not update the view in the browser.
Vue instance code:
var vm = new Vue({
delimiters: ['$[', '$]'], //change delimiters to allow django integration
el: '#vue_app',
data: {
title: init_info.title, //page title
active: 'presentations',
navClass: 'nav-item nav-link', //necessary for navbar rendering
features: features,
question: '',
response: '',
feature_id: init_info.opening,
last_feature: '',
clarif_id: '',
clarifyings: [],
show_clarifying: false,
},
Relevant method update:
fetch(url)
.then(response => response.json())
.then(function (data) {
// Type out question and response
typeWriter(data.question, 'question');
typeWriter(data.answer, 'response');
// Save selected option and disable previous selected option
option_disable(vm.last_feature);
vm.last_feature = option_ref;
// Show clarifying questions
vm.clarifyings = data.clarifyings;
if (vm.clarifyings.length){
vm.show_clarifying = true;
}
else {
vm.show_clarifying = false;
}
}
All of this executes normally it is simply the re-rendering that isn't working. If I specify the array when I initialize the Vue instance it renders properly it simply does not update.
HTML code:
<select class="selectpicker" data-live-search="true" v-model="clarif_id">
<option v-for="question in clarifyings">$[question.id$] - $[question.name$]</option>
</select>
Vuejs has a bad reactivity for arrays. See the official doc : https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
You can use Vue.set(vm.clarifyings, indexOfItem, newValue) to overcome this problem. (Instead of vm.clarifyings.push(object))
The problem appeared to be a result of interference with bootstrap-selectpicker, it was fixed by using nextTick functionality in vue like so:
if (feature_asked) {
vm.clarifyings = data.clarifyings;
if (vm.clarifyings.length) {
vm.show_clarifying = true;
vm.$nextTick(function () {
$("#clarifying_qs").selectpicker("refresh");
});
I'm trying to populate a pie chart with some JSON-data. My datasource is restcountries.eu/rest/v2/all. I retrieve the data with a $.getJSON and I create a temporary array which in turn is used as a datasource. I then bind the source to the pie chart. That what I think I'm doing atleast..
The error I'm getting is following
my-piechart-viewModel.js:25 Uncaught (in promise) ReferenceError: data is not
defined
at new myPieChartModel (my-piechart-viewModel.js:25)
at Object.CreateComponent (ojcomposite.js:1808)
at ojcustomelement.js:385
My code looks like this
HTML
<oj-chart id="pieChart1" aria-label= 'TestPieChart'
type="pie"
series='[[datasource]]'
style="max-width:500px;width:100%;height:350px;">
</oj-chart>
JS
function myPieChartModel() {
var self = this;
self.data = ko.observableArray();
$.getJSON("https://restcountries.eu/rest/v2/all").
then(function(countries) {
var tempArray = [];
$.each(countries, function() {
tempArray.push({
name: this.name,
population: this.population
});
});
self.data(tempArray);
});
self.datasource = ko.observableArray(data);
}
return myPieChartModel;
What am I doing wrong? I'm very new to Oracle's JET, and I have very little experience with JSON overall.
If you defined something as self.data you cannot later access it by calling just data. So you need to change your last line to:
self.datasource = ko.observableArray(self.data);
Even if you do do that, you'll get this error:
The argument passed when initializing an observable array must be an array, or null, or undefined.
That is, you cannot pass an observableArray into an observableArray. self.data should just be a normal JS array.
self.data = [];
But a normal JS array does not fire any events when its values are changed, so you'll need to update the observableArray datasource again. Your full code can be like this:
function myPieChartModel() {
var self = this;
self.data = [];
self.datasource = ko.observableArray(self.data);
$.getJSON("https://restcountries.eu/rest/v2/all").
then(function(countries) {
$.each(countries, function() {
self.data.push({
name: this.name,
population: this.population
});
});
self.datasource(self.data);
});
}
return myPieChartModel;
Let me know if it works. I have a feeling that your JSON data will also need to be modified like this:
self.data.push({name: this.name,
items: [this.population]
});
Why? Because that's how Oracle JET expects it. Here's the documentation.
EDIT: Live Code Editor added: https://ide.c9.io/dosstx/wordpress
I am trying to filter a Wordpress JSON data object using VueJS2 and the Wordpress REST API (I have a custom post type in my real world example).
I'm having trouble with the wiring and getting the table to filter based on the search terms that are typed into the search box.
Without the search function, everything works fine, but once I try to filter using a searchterm, nothing happens -- no error in console.
I have my Vue instance like so:
var vm = new Vue({
el: '#app',
data: {
searchTerm: '',
posts: []
},
computed: {
filteredItems: function(){
return this.posts.filter(function(post) {
return this.post.searchTerm; //i believe this line is the culprit
});
}
},
created: function(){
$.get('mylocalhost/wp-json/wp/v2/products/' + '?_embed=true')
.done(function(data) {
vm.posts = data;
});
}
});
My HTML:
<div id="app">
<form>
<input type="text" v-model="searchTerm">
</form>
And further down my HTML....:
<tr v-for="post in filteredItems">
<td>{{post.title.rendered}}</td>
...snip ...
</div>
Any clues on how to fix would be greatly appreciated.
You aren't using the filter method correctly.
From the MDN Docs for the filter method:
filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true.
The callback passed to filter should return a Boolean value to determine whether or not to include the element of the array in the filtered array.
In your case, I'm assuming your post objects have some property (say content) you want to search and that you want to only include posts with content that contain the search term. So you can do something like this:
computed: {
filteredItems: function() {
return this.posts.filter(function(post) {
return post.content.indexOf(this.searchTerm) != -1;
});
}
},
I am fooling around with a loop and a ajax request in react I cannot seem to get working. Its suppose to loop over, set the object array and then push that object array to the state for later use.
The issue is that I am failing at promises in general. I am using this concept from the react docs to set the state of a component upon mounting to return an array of "links".
/** #jsx React.DOM */
var Temp = {
object: new Array()
}
var CommentsRow = React.createClass({
getInitialState: function(){
return {
href: ''
}
},
componentDidMount: function(){
var self = this
this.props.comments.slice(0, 5).map(function(comment){
var postUrl = window.Development.API_URL + 'posts/' + comment.post_id
$.get(postUrl, function(post){
Temp.object.push(post.post.title);
if (self.isMounted()) {
self.setState({
href: Temp.object
});
}
});
});
},
render: function() {
console.log(this.state)
}
});
The gist of whats going on above is:
I have a bunch of comments coming in and I take the first five. From there I loop over each comment object and grab the title, creating my api link. With that I want to say get me the post based on this link, assuming it works we then want to set a temp object, this will create "five arrays" each going from a count of 1,2,3,4 and finally 5 elements.
from there we take that and set the state. This part works, but because its a ajax request the state out side the request is empty even if I use the if (isMounted()){ ... } option.
any idea how I can set the state doing something like this and still have access to it?
You either want async.js or promises to help manage multiple async actions. Async integrates a bit better with jQuery, so I'll show it with that.
componentDidMount: function(){
async.map(this.props.comments.slice(0, 5), function(comment, cb){
var postUrl = window.Development.API_URL + 'posts/' + comment.post_id;
$.get(postUrl, function(data){
cb(null, {title: data.post.title, href: ???});
});
}, function(err, posts){
// posts is an array of the {title,href} objects we made above
this.setState({posts: posts});
}.bind(this));
}
I am building what should be a fairly simple project which is heavily based on Ampersand's starter project (when you first run ampersand). My Add page has a <select> element that should to be populated with data from another collection. I have been comparing this view with the Edit page view because I think they are quite similar but I cannot figure it out.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
Below you can see that I am trying to fetch the app.brandCollection and set its value to this.model, is this correct? I will need to modify the output and pass through the data to an ampersand-select-view element with the correct formatting; that is my next problem. If anyone has suggestions for that I would also appreciate it.
var PageView = require('./base');
var templates = require('../templates');
var ProjectForm = require('../forms/addProjectForm');
module.exports = PageView.extend({
pageTitle: 'add project',
template: templates.pages.projectAdd,
initialize: function () {
var self = this;
app.brandCollection.fetch({
success : function(collection, resp) {
console.log('SUCCESS: resp', resp);
self.brands = resp;
},
error: function(collection, resp) {
console.log('ERROR: resp', resp, options);
}
});
},
subviews: {
form: {
container: 'form',
waitFor: 'brands',
prepareView: function (el) {
return new ProjectForm({
el: el,
submitCallback: function (data) {
app.projectCollection.create(data, {
wait: true,
success: function () {
app.navigate('/');
app.projectCollection.fetch();
}
});
}
});
}
}
}
});
This is only the add page view but I think that is all that's needed.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
This string represents path in a current object with fixed this context. In your example you've waitFor: 'brands' which is nothing more than PageView.brands here, as PageView is this context. If you'd have model.some.attribute, then it'd mean that this string represents PageView.model.some.attribute. It's just convenient way to traverse through objects.
There's to few informations to answer your latter question. In what form you retrieve your data? What do you want to do with it later on?
It'd be much quicker if you could ping us on https://gitter.im/AmpersandJS/AmpersandJS :)