I am trying to make a json webapp which reads from apis and prints the result into a list.
The problem is that i cannot read the complete json object on render.
console.log(this.state.coinInfo);
coinInfo is a json object looking like:
quantstamp: {id: "quantstamp", name: "Quantstamp", symbol: "QSP", rank: "107", price_usd: "0.446127", …},
vechain: {id: "vechain", name: "VeChain", symbol: "VEN", rank: "30", price_usd: "5.80186", …}
writing:
this.state.coinInfo["vechain"] works, but
this.state.coinInfo["vechain"].id says undefined.
I would love to get the coinInfo informations into the element on render.
Here is the full code:
var Dashboard = React.createClass({
getInitialState: function() {
return {
coinListJson: "json/coinlist.json",
coinList: [],
coinInfo: {}
}
},
createDashboard: function(event) {},
componentDidMount: function() {
// Is there a React-y way to avoid rebinding `this`? fat arrow?
var th = this;
var coinListBuffer;
var coinInfoBuffer = {};
this.serverRequest = axios.get(this.state.coinListJson).then(function(result) {
coinListBuffer = result.data.coins;
th.setState({
coinList: result.data.coins
})
}).then(function() {
//alert("geht "+coinListBuffer[1].id);
coinListBuffer.map(function(val, index) {
var url = "https://api.coinmarketcap.com/v1/ticker/" + val.id + "/?convert=EUR";
th.serverRequest = axios.get(url).then(function(result) {
coinInfoBuffer[val.id] = result.data;
console.log(result.data[0]);
var coinInfoBufferString = coinInfoBuffer;
th.setState({
coinInfo: coinInfoBufferString
})
})
})
})
},
render: function() {
var th = this;
console.log(this.state.coinInfo);
return (
<ul>
{
this.state.coinList.map(function(val, index) {
return (
<li key={index}>
{val.id}
</li>);
})
}
</ul>
)
}
});
Related
I have been stuck with this issues for 2 hours now and I really can't seem to get it work.
const app = new Vue({
el: '#book-search',
data: {
searchInput: 'a',
books: {},
},
methods: {
foo: function () {
axios.get('https://www.googleapis.com/books/v1/volumes', {
params: {
q: this.searchInput
}
})
.then(function (response) {
var items = response.data.items
for (i = 0; i < items.length; i++) {
var item = items[i].volumeInfo;
Vue.set(this.books[i], 'title', item.title);
}
})
.catch(function (error) {
console.log(error);
});
}
}
});
When I initiate search and the API call I want the values to be passed to data so the final structure looks similar to the one below.
data: {
searchInput: '',
books: {
"0": {
title: "Book 1"
},
"1": {
title: "Book 2"
}
},
Currently I get Cannot read property '0' of undefined.
Problem lies here:
Vue.set(this.books[i], 'title', item.title);
You are inside the callback context and the value of this is not the Vue object as you might expect it to be. One way to solve this is to save the value of this beforehand and use it in the callback function.
Also instead of using Vue.set(), try updating the books object directly.
const app = new Vue({
el: '#book-search',
data: {
searchInput: 'a',
books: {},
},
methods: {
foo: function () {
var self = this;
//--^^^^^^^^^^^^ Save this
axios.get('https://www.googleapis.com/books/v1/volumes', {
params: {
q: self.searchInput
//-^^^^--- use self instead of this
}
})
.then(function (response) {
var items = response.data.items
var books = {};
for (i = 0; i < items.length; i++) {
var item = items[i].volumeInfo;
books[i] = { 'title' : item.title };
}
self.books = books;
})
.catch(function (error) {
console.log(error);
});
}
}
});
Or if you want to use Vue.set() then use this:
Vue.set(self.books, i, {
'title': item.title
});
Hope this helps.
yep, the problem is about context. "this" returns not what you expect it to return.
you can use
let self = this;
or you can use bind
function(){this.method}.bind(this);
the second method is better.
Also google something like "how to define context in js", "bind call apply js" - it will help you to understand what is going wrong.
// update component's data with some object's fields
// bad idea, use at your own risk
Object
.keys(patch)
.forEach(key => this.$data[key] = patch[key])
Please forgive if I am way off target, but I am trying to set a component's state to a json object, so that I can render it with the component.
Here is what a currently have inside my component:
render: function() {
this.serverRequest = $.get(this.props.source, function (data) {
this.state.content = $.parseJSON(data);
}.bind(this));
return (
<div>
{Object.keys(this.state.content).map(function (key) {
return <div>Key: {key}, Value: {this.state.content[key]}</div>;
})}
</div>
);
With this code I currently get:
Uncaught TypeError: Cannot read property 'state' of undefined
Anyone have any insight as to why this isn't working?
The problem is, the this inside the $.get() is not in the React's scope. And calling setState() inside render will throw an error. The following should help...
var App = React.createClass({
getInitialState: function() {
return {
content: {},
}
},
componentDidMount: function() {
this.serverRequest()
},
serverRequest: function() {
var _this = this
$.get(this.props.source, function(data) {
_this.state.content = $.parseJSON(data);
})
},
render: function() {
return ( < div >
{
Object.keys(this.state.content).map(function(key) {
return <div > Key: {
key
}, Value: {
this.state.content[key]
} < /div>;
})
}
< /div >
);
}
})
I have this following code
var SelectOption = React.createClass({
getInitialState: function() {
return {
data: []
};
},
handleemployeeChange: function() {
alert('sssss');
},
loadOptionfromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({
data: data
});
console.log(data);
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
alert('sssss');
this.loadOptionfromServer();
//setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
render: function() {
return ( < SelectOptionList data = {
this.state.data
}
/>
);
}
});
var SelectOptionList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(list) {
return ( < Addcontenttoselect id = {
list.emp_ide_id
}
option = {
list.emp_name
} >
< /Addcontenttoselect>
);
});
return ( < select id = "select1"
className = "form-control"
data - placeholder = "Basic Select2 Box"
onChange = {
this.handleemployeeChange
} > {
commentNodes
} < /select>
);
}
});
var Addcontenttoselect = React.createClass({
render: function() {
return ( < option value = "{this.props.id}" > {
this.props.option
} < /option>);
}
});
ReactDOM.render( < div className = "col-md-3" > < h3 > Select Employee to Review < /h3><SelectOption url="/appraisal / employeelist " pollInterval={70000} /></div>, document.getElementById('select-box'));
So this component creates a Select Tag in the browser , I want to take the Value of the selected option and Call another component which will create a Table from a data got from API
Any leads please let me know
Thanks
With react you have multiple ways to pass around data to your components, it depends heavily on the use and the complexity of your application.
If you have a lot of components which need to know about the state/data of another component you should look at application architectures like flux or redux. Facebooks Flux
For some applications a full data flow architecture can be overkill so it depends on how you design your components. A common pattern is to have one component who handles the state/interactivity of your application.
Your main component will hold all the business logic of your app and pass down functions to its child to e.g. change state.
You can read more about this here Facebook thinking react
I did a little fiddle which adresses your challenge:
Fiddle
var Select = React.createClass({
render: function() {
var selectOptions = this.props.options.map(function(optionData) {
return (
<option key={optionData.id} value={optionData.id}>
{optionData.name}
</option>
);
});
return (
<select
id="select1"
className="form-control"
placeholder="Basic Select2 Box"
onChange={this.props.onChange}
>
{ selectOptions }
</select>
);
}
});
var SelectApp = React.createClass({
// The main component holds the data
getInitialState: function() {
return {
data: [],
currentData: null
}
},
componentDidMount: function () {
this.loadOptions();
},
loadOptions: function () {
var _this = this;
return setTimeout(function() {
_this.setState({data: [
{
id: 1,
name: 'Foo Bar'
},
{
id: 2,
name: 'Bar Foo'
}
]});
}, 2000);
},
onChange: function (e) {
var employeeId = e.target.value,
_this = this,
mockedData = [
{
id: 1,
data: 'Good employee'
},
{
id: 2,
data: 'Not so good employee'
}
];
// Mocking an additional data fetch
setTimeout(function () {
var result = mockedData.find(function (employeeData) {
return (employeeData.id == employeeId);
});
_this.setState({
currentData: result
});
}, 2000);
},
renderResult: function () {
if (this.state.currentData) {
return (
<div>
<h4>Employee:</h4>
<p>{this.state.currentData.data}</p>
</div>
);
}
return;
},
render: function() {
return (
<div>
<div>
<h3> Select Employee to Review </h3>
<Select url={this.props.url} options={this.state.data} onChange={this.onChange}/>
</div>
{this.renderResult()}
</div>
);
}
});
ReactDOM.render(<SelectApp url="/appraisal / employeelist " pollInterval={70000} />, document.getElementById('container'));
Edit:
renderResult: function () {
if (this.state.currentData) {
return (
<loadUserAppraisal url="something" empid={this.state.currentData.id} />
);
}
I have the following code:
var RiderComponent = React.createClass({
updater: function(){
this.props.metadata.update();
},
render: function () {
return (
<a href="#" onClick={this.updater}>
click!
</a>
);
}
});
var RiderList = React.createClass({
columnMeta: [
{
"columnName": "action",
"displayName": "",
"cssClassName": "buy",
"order": 6,
"customComponent": RiderComponent,
"update": this.update
}
],
update: function () {
this.props.update();
},
render: function () {
return <Griddle results={this.props.data}
useGriddleStyles={false}
showFilter={true}
columnMetadata={this.columnMeta}
columns={['action']}
resultsPerPage={18}
initialSort={'value'}
initialSortAscending={false}
noDataMessage={'Geen wielrenners gevonden.'}
/>
}
});
I want to run the update() function from RiderList in my RiderComponent when I click on an item. However I keep getting: 'Uncaught TypeError: this.props.metadata.update is not a function'.
What is the correct way to execute the update function in my RiderComponent?
RiderList is rendered in TeamManager:
var TeamManager = React.createClass({
getInitialState: function () {
return {
results: [],
activeRiders: [],
extraRiders: [],
availablePositions: []
}
},
componentWillMount: function () {
this.getExternalData();
},
getExternalData: function () {
var race_id = 1; // TODO: this is hardcoded
request = Api.getRidersPageUrl(race_id);
$.get(request, function (rsp) {
var data = rsp;
var activeRiders = []; // Riders with position 0..8
var extraRiders = []; // Riders with position 9..14
var availablePositions = Array.apply(null, {length: 9}).map(Number.call, Number); // Array 0..8;
if (data) {
// set data to arrays here
}
this.setState({
results: data,
activeRiders: activeRiders,
extraRiders: extraRiders,
availablePositions: availablePositions
});
}.bind(this));
},
render: function () {
return (
<RiderList update={this.getExternalData} data={this.state.results}/>
)
}
});
module.exports = TeamManager;
Here this.getExternalData just reloads the data in this.state.results.
EDIT: I got something working while using onRowClick={this.update} in RiderList render . However this fires when I click the row and not a specific button IN the row.
Updated answer based upon question new info,
var RiderComponent = React.createClass({
render: function () {
return (
<a onClick={this.props.metadata.update}>
click!
</a>
);
}
});
var RiderList = React.createClass({
getColumnMeta: function(){
return[
{
"columnName": "action",
"displayName": "",
"cssClassName": "buy",
"order": 6,
"customComponent": RiderComponent,
"update": this.update
}
]
},
update: function () {
this.props.update();
},
render: function () {
return <Griddle results={this.props.data}
useGriddleStyles={false}
showFilter={true}
columnMetadata={this.getColumnMeta()}
columns={['action']}
resultsPerPage={18}
initialSort={'value'}
initialSortAscending={false}
noDataMessage={'Geen wielrenners gevonden.'}
/>
}
});
I'm starting to learn and azure phonejs.
Todo list get through a standard example:
$(function() {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
// Read current data and rebuild UI.
// If you plan to generate complex UIs like this, consider using a JavaScript templating library.
function refreshTodoItems() {
var query = todoItemTable.where({ complete: false });
query.read().then(function(todoItems) {
var listItems = $.map(todoItems, function(item) {
return $('<li>')
.attr('data-todoitem-id', item.id)
.append($('<button class="item-delete">Delete</button>'))
.append($('<input type="checkbox" class="item-complete">').prop('checked', item.complete))
.append($('<div>').append($('<input class="item-text">').val(item.text)));
});
$('#todo-items').empty().append(listItems).toggle(listItems.length > 0);
$('#summary').html('<strong>' + todoItems.length + '</strong> item(s)');
}, handleError);
}
function handleError(error) {
var text = error + (error.request ? ' - ' + error.request.status : '');
$('#errorlog').append($('<li>').text(text));
}
function getTodoItemId(formElement) {
return $(formElement).closest('li').attr('data-todoitem-id');
}
// Handle insert
$('#add-item').submit(function(evt) {
var textbox = $('#new-item-text'),
itemText = textbox.val();
if (itemText !== '') {
todoItemTable.insert({ text: itemText, complete: false }).then(refreshTodoItems, handleError);
}
textbox.val('').focus();
evt.preventDefault();
});
// Handle update
$(document.body).on('change', '.item-text', function() {
var newText = $(this).val();
todoItemTable.update({ id: getTodoItemId(this), text: newText }).then(null, handleError);
});
$(document.body).on('change', '.item-complete', function() {
var isComplete = $(this).prop('checked');
todoItemTable.update({ id: getTodoItemId(this), complete: isComplete }).then(refreshTodoItems, handleError);
});
// Handle delete
$(document.body).on('click', '.item-delete', function () {
todoItemTable.del({ id: getTodoItemId(this) }).then(refreshTodoItems, handleError);
});
// On initial load, start by fetching the current data
refreshTodoItems();
});
and it works!
Changed for the use of phonejs and the program stops working, even mistakes does not issue!
This my View:
<div data-options="dxView : { name: 'home', title: 'Home' } " >
<div class="home-view" data-options="dxContent : { targetPlaceholder: 'content' } " >
<button data-bind="click: incrementClickCounter">Click me</button>
<span data-bind="text: listData"></span>
<div data-bind="dxList:{
dataSource: listData,
itemTemplate:'toDoItemTemplate'}">
<div data-options="dxTemplate:{ name:'toDoItemTemplate' }">
<div style="float:left; width:100%;">
<h1 data-bind="text: name"></h1>
</div>
</div>
</div>
</div>
This my ViewModel:
Application1.home = function (params) {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
var toDoArray = ko.observableArray([
{ name: "111", type: "111" },
{ name: "222", type: "222" }]);
var query = todoItemTable.where({ complete: false });
query.read().then(function (todoItems) {
for (var i = 0; i < todoItems.length; i++) {
toDoArray.push({ name: todoItems[i].text, type: "NEW!" });
}
});
var viewModel = {
listData: toDoArray,
incrementClickCounter: function () {
todoItemTable = client.getTable('todoitem');
toDoArray.push({ name: "Zippy", type: "Unknown" });
}
};
return viewModel;
};
I can easily add items to the list of programs, but from the server list does not come:-(
I am driven to exhaustion and can not solve the problem for 3 days, which is critical for me!
Specify where my mistake! Thank U!
I suggest you use a DevExpress.data.DataSource and a DevExpress.data.CustomStore instead of ko.observableArray.
Application1.home = function (params) {
var client = new WindowsAzure.MobileServiceClient('https://zaburrito.azure-mobile.net/', 'key');
var todoItemTable = client.getTable('todoitem');
var toDoArray = [];
var store = new DevExpress.data.CustomStore({
load: function(loadOptions) {
var d = $.Deferred();
if(toDoArray.length) {
d.resolve(toDoArray);
} else {
todoItemTable
.where({ complete: false })
.read()
.then(function(todoItems) {
for (var i = 0; i < todoItems.length; i++) {
toDoArray.push({ name: todoItems[i].text, type: "NEW!" });
}
d.resolve(toDoArray);
});
}
return d.promise();
},
insert: function(values) {
return toDoArray.push(values) - 1;
},
remove: function(key) {
if (!(key in toDoArray))
throw Error("Unknown key");
toDoArray.splice(key, 1);
},
update: function(key, values) {
if (!(key in toDoArray))
throw Error("Unknown key");
toDoArray[key] = $.extend(true, toDoArray[key], values);
}
});
var source = new DevExpress.data.DataSource(store);
// older version
store.modified.add(function() { source.load(); });
// starting from 14.2:
// store.on("modified", function() { source.load(); });
var viewModel = {
listData: source,
incrementClickCounter: function () {
store.insert({ name: "Zippy", type: "Unknown" });
}
};
return viewModel;
}
You can read more about it here and here.