Array that is filled with objects has wrong length? - javascript

I'm creating a React-native app, and I'm getting some data with AsyncStorage which I transform into an Array with Objects which will be combined/concatnated with data that I fetch from an API
const available_streams = streams.channels.filter(stream => !stream.is_live)
const the_streams = available_streams.map(available_stream => {
available_stream.checked = false
return available_stream
})
console.log(the_streams) :
(3) [{…}, {…}, {…}]
0: {name: "channel1", url: "wss%3A%2F%2Fwebsite.com", app_name: "streams", server_name: "channel1", is_live: false, …}
1: {name: "channel3", url: "wss%3A%2F%2Fwebsite.com", app_name: "streams", server_name: "channel3", is_live: false, …}
2: {app_name: "sms", url: "website.com:4443", server_name: "93b5d83448", name: "Test", is_live: false, …}
length: 3
let saved_stream_names = []
// LOCAL VALUES
get_session_value('url').then(url => {
get_session_object('stream_names')
.then(stream_names => {
stream_names.forEach(name => {
saved_stream_names.push({
name: name,
checked: false,
is_live: false,
url: url
})
})
})
})
Array.prototype.push.apply(saved_stream_names, the_streams)
console.log(saved_stream_names)
the console.log prints the following:
(3) [{…}, {…}, {…}] <---- !! WHY 3 ?!!
0: {name: "channel1", url: "wss%3A%2F%2F.website.com", app_name: "streams", server_name: "channel1", is_live: false, …}
1: {name: "channel3", url: "wss%3A%2F%2Fwebsite.com", app_name: "streams", server_name: "channel3", is_live: false, …}
2: {app_name: "sms", url: "wss://website3:4443/", server_name: "93b5d83448", name: "Test", is_live: false, …}
3: {name: "Xxx", checked: false, is_live: false, url: "https://website.com/"}
4: {name: "Next", checked: false, is_live: false, url: "website.com"}
5: {name: "Arghhj", checked: false, is_live: false, url: "https://website.com/"}
length: 6
also console.log(saved_stream_names.length) says it's 3 in size
and i cannot loop over the last 3 objects. What kind of wizardry is this?

It is a synchronicity problem.
get_session_value('url')
Returns a promise, the code inside the then() will only execute when this promise is solved.
Even tho console.log(saved_stream_names) is the last line of code, it is being executed before the code inside the then(). Try moving the console.log to inside the then:
let saved_stream_names = []
// LOCAL VALUES
get_session_value('url').then(url => {
get_session_object('stream_names')
.then(stream_names => {
stream_names.forEach(name => {
saved_stream_names.push(
({
name: name,
checked: false,
is_live: false,
url: url
})
)
})
console.log(saved_stream_names)
})
})
Array.prototype.push.apply(saved_stream_names, the_streams)

I believe it might be because console.log gets called before get_session_value() finishes running. So when console.log is printed it only contains the values of the_streams. However since it is referencing an array, it will show the whole thing by the time you look at it. You can confirm this by doing console.log(JSON.stringify(saved_stream_names)).
I would suggest you put these lines of code:
Array.prototype.push.apply(saved_stream_names, the_streams)
console.log(saved_stream_names)
inside the get_session_object.then() function.

Related

Angular Array not updating after maping function

I have an array of Categories that I filter when a user click on a button that selects a specific categories to view. however after maping the categories array, the categories display the desired result in the console however it seems to get lost somehow and the categories dont update in the DOM?
ngOnInit() {
this.initCategories();
this.shopService.filterCategories.subscribe(
(fCategory: string) => {
const filteredCategories = this.categories.filter(category => {
return category.name !== fCategory;
});
for (const obj of filteredCategories) {
obj.checked = false;
}
const newCategories = [];
this.categories.map(obj => {
filteredCategories.filter(fCat => obj);
newCategories.push(obj);
});
this.categories = newCategories;
console.log(this.categories)
}
);
}
initCategories(){
this.categories = [
{name: 'dress', checked: true, displayName: 'Dresses'},
{name: 'top', checked: true, displayName: 'Shirts'},
{name: 'skirt', checked: true, displayName: 'Skirts/Pants'},
{name: 'purse', checked: true, displayName: 'Purse'},
{name: 'bag', checked: true, displayName: 'Bags'},
];
}
result
[{…}, {…}, {…}, {…}, {…}]
0: {name: "dress", checked: true, displayName: "Dresses"}
1: {name: "top", checked: false, displayName: "Shirts"}
2: {name: "skirt", checked: false, displayName: "Skirts/Pants"}
3: {name: "purse", checked: false, displayName: "Purse"}
4: {name: "bag", checked: false, displayName: "Bags"}
however when I log the categories array in ngAfterViewInit
I get this.
[{…}, {…}, {…}, {…}, {…}]
0: {name: "dress", checked: true, displayName: "Dresses"}
1: {name: "top", checked: true, displayName: "Shirts"}
2: {name: "skirt", checked: true, displayName: "Skirts/Pants"}
3: {name: "purse", checked: true, displayName: "Purse"}
4: {name: "bag", checked: true, displayName: "Bags"}
what I tried
this.shopService.filterCategories.subscribe(
(fCategory: string) => {
const filteredCategories = this.categories.filter(category => {
return category.name !== fCategory;
});
for (const obj of filteredCategories) {
obj.checked = false;
}
let newCategories;
newCategories = [...this.categories.map(obj => {
filteredCategories.filter(fCat => obj);
})];
this.categories = newCategories;
console.log(this.categories)
}
);
}
I think you need to play with
this.categories.map(obj => {
filteredCategories.filter(fCat => obj);
both of them return a new array, they don't touch current one.
Therefore I would assume that filteredCategories.filter at least should be assigned somewhere.
// an empty array
const newCategories = [];
// starting a loop, forEach would fit here better because it doesn't return anything.
this.categories.map(obj => {
// the result of this filter won't be assigned anywhere.
filteredCategories.filter(fCat => obj);
// pushing obj to newCategories for every iteration.
// may be you need to wrap it with `if` based on filter result.
newCategories.push(obj);
});
// newCategories is an array with the same items as this.categories.
// because we simply iterate without any conditions.
console.log(newCategories);
In the update part of your question filter still doesn't do anything.
Its result should be assigned or used in a condition.
newCategories = [...this.categories.map(obj => {
filteredCategories.filter(fCat => obj); // <- should be assigned
})];
if you want to add only filtered only active category.
ngOnInit() {
this.initCategories();
this.shopService.filterCategories.subscribe(
(fCategory: string) => {
const filteredCategories: FilterBarComponent['categories'] = [];
for (const category of this.categories) {
filteredCategories.push({
...category,
checked: category.name === fCategory,
});
}
this.categories = filteredCategories;
this.updateCategories();
}
);
}

setState doesn't set values

We got a ReactJS frontend delivered for our school project. We have to make a Laravel backend for it. I'm using an API to fetch the dashboard layout from the database. The current frontend makes use of this variable:
const originalLayouts = getFromLS("layouts") || [];
To set the state from the local storage with this function:
function getFromLS(key) {
let ls = {};
if (global.localStorage) {
try {
ls = JSON.parse(global.localStorage.getItem("rgl-8")) || {};
} catch (e) {
/*Ignore*/
}
}
return ls[key];
}
Where the states are set:
this.state = {
items: originalLayouts.map(function(i, key, list) {
return {
i: originalLayouts[key].i,
x: originalLayouts[key].x,
y: originalLayouts[key].y,
w: originalLayouts[key].w,
h: originalLayouts[key].h,
widget: originalLayouts[key].widget,
minW: originalLayouts[key].minW,
minH: originalLayouts[key].minH,
maxH: originalLayouts[key].maxH
};
}),
selectedOption: '',
newCounter: originalLayouts.length
};
To fetch the data from the database and put the data into the items state I made this function:
loadData = () => {
let dashboardId = 1;
return axios
.get('api/dashboards/' + dashboardId)
.then(result => {
console.log(result);
this.setState({
originalLayouts: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
console.log(result.data);
})
.catch(error => {
console.error('error: ', error);
})
};
And I call this function in componentDidMount:
componentDidMount() {
this.loadData();
}
When I console log result it shows me this:
data: Array(2), status: 200, statusText: "OK", headers: {…}, config: {…}, …}
config: {adapter: ƒ, transformRequest: {…}, transformResponse: {…}, timeout: 0, xsrfCookieName: "XSRF-TOKEN", …}
data: (2) [{…}, {…}]
headers: {date: "Tue, 23 Oct 2018 08:18:41 +0000, Tue, 23 Oct 2018 08:18:41 GMT", host: "127.0.0.1:8000", x-powered-by: "PHP/7.2.3", x-ratelimit-remaining: "58", content-type: "application/json", …}
request: XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
status: 200
statusText: "OK"
__proto__: Object
And when I console log result.data I get:
(2) [{…}, {…}]
0: {id: 1, dashboardId: 1, w: 2, h: 5, x: 0, …}
1: {id: 2, dashboardId: 1, w: 2, h: 1, x: 0, …}
length: 2
__proto__: Array(0)
Why is originalLayouts not set with the data from the arrays? Is this because I also have a dashboardId and id in my arrays? I also thought it could be something with setting the states because it makes use of the originalLayouts veriable. Or am I still missing something in my function? I'm not very experienced with React so any help is useful.
Update:
I changed:
this.setState({
originalLayouts: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
to:
this.setState({
items: result.data,
selectedOption: '',
newCounter: originalLayouts.length
});
This gives me this error:
Uncaught Error: ReactGridLayout: ReactGridLayout.children[0].static must be a boolean!
So that probably means I'm not setting the properties properly now.
Update 2:
In my database the properties moved and static were saved as 0 instead of false. So I changed those properties to false but I still got the same error:
ReactGridLayout: ReactGridLayout.children[0].static must be a boolean!
In your loadData(), you are setting the state of "originalLayouts" but your key in your initial state is "items". Have you tried to do this ?
this.setState({
items: result.data, // Here put items instead of originalLayouts
selectedOption: '',
newCounter: originalLayouts.length
});
Then you can call this.state.items to get your result.data

Setstate of specific object in array

I have a cats array that I pull from an api
i map over these and render them on a page
each one gets rendered with a like button, when I hit like I want it to like it and when i hit like again, it should unlike it
my initialState is :
state = {
cats: []
};
then once i call the api state looks like this:
cats: [
{url: Array(1), id: Array(1), source_url: Array(1), liked: false}
{url: Array(1), id: Array(1), source_url: Array(1), liked: false}
]
I have a like cat method whereby I find the cat that I liked like this:
var cat = this.state.cats.find(c => c.id[0] === cat.id[0])
considering I have all this information, how do I call setState for that specific cat to change the liked from false to true?
I was thinking something like this:
this.setState(prevState => ({ cats: {
cat: {
...prevState.cat,
liked: !prevState.cat.liked
}
}}))
but it does not know what liked is of undefined
any ideas?
One problem with your approach is that there's no prevState.cat.
Assuming the (un)liked cat is stored in cat:
this.setState(prevState => ({
cats: prevState.cats.map(c => c.id[0] === cat.id[0] ? Object.assign(c, { liked: !c.liked }) : c)
}));
Demo:
var state;
function setState(a) {
state = Object.assign(state, a(state));
}
state = {
cats: [
{url: [0], id: [1], source_url: [0], liked: false},
{url: [0], id: [2], source_url: [0], liked: false}
]
};
var cat = state.cats[1];
setState(prevState => ({
cats: prevState.cats.map(c => c.id[0] === cat.id[0] ? Object.assign(c, { liked: !c.liked }) : c)
}));
console.log(state.cats[1].liked);

Formatting json data into table React.js

I have this state defined:
constructor(props){
super(props);
this.state = {
open: false,
customers:[],
customer:{},
products:[],
product:{},
orders:[],
order:{},
newForm:true,
phoneNumbererror:null,
shop:this.props.salon,
value:'a',
showTab:'none',
slideIndex: 0,
};
}
With the following function which contains a fetch, I recieve an array of objects with responseData.
getHistory(){
console.log("Log antes del fetch de customer id");
console.log(this.state.customer._id);
fetch(
DOMAIN+'/api/orders/customer/'+this.state.customer._id, {
method: 'get',
dataType: 'json',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization':'Bearer '+this.props.token
}
})
.then((response) =>
{
return response.json();
})
.then((responseData) => {
let orders = responseData.map((order) => {
return order.orderStatusChange ? Object.assign({}, order, {
status: order.orderStatusChange[0].status
}) : order;
});
this.setState({orders:orders});
console.log("Log del responseData");
console.log(responseData);
console.log(responseData.orderStatusChange[0]);
})
.catch(function() {
console.log("error");
});
}
This function is called in handleCellClick, where I pass some data from the consumer, such as the ID:
handleCellClick(y,x,row){
this.setState({
open:true,
slideIndex: 0,
newForm:false,
customer:{...row}
});
this.getProfiles();
this.getHistory();
}
The JSON object obtained from the fetch and kept within this.state.orders looks like this:
(29) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0:
created:"2017-07-06T15:58:07.958Z"
customer:"59561f3f1d178e1966142ad7"
lastModified:"2017-07-06T15:58:07.958Z"
orderList:[]
orderStatusChange:Array(1)
0:{status: "5", comments: "Creado en back antes de pagar", _id: "595e5e0f60fbf65149916b7c", created: "2017-07-06T15:58:07.958Z"}
length:1
__proto__:Array(0)
shop:"59108159bc3fc645704ba508"
totalAmount:4000
__v:0
_id:"595e5e0f60fbf65149916b7b"
__proto__:Object
As shown previously in the fetch, with this line this.setState({orders:responseData}) I can pass orders to the table where I want the id, date, status and price to be displayed:
<DataTables
height={'auto'}
selectable={false}
showRowHover={true}
columns={HISTORY_TABLE_COLUMNS}
data={this.state.orders}
showCheckboxes={false}
rowSizeLabel="Filas por página"
/>
The table called is:
const HISTORY_TABLE_COLUMNS = [
{
key: '_id',
label: 'Número de pedido',
style:{width: '37%'}
}, {
key: 'created',
label: 'Fecha del pedido',
style:{width: '33%'}
}, {
key: 'status',
label: 'Estado',
style:{width: '13%'}
}, {
key: 'totalAmount',
label: 'Total',
style:{width: '17%'}
}
];
How can I format the price (totalAmount) to have 2 decimals and print next to it the € symbol?
CAPTURE FOR BETTER UNDERSTANDING
This solution works fine with node module material-ui-datatables version 0.18.0
You can use render method in column settings to work on the column data.
const currencyToAppend = '€';
const HISTORY_TABLE_COLUMNS = [
{
....
}, {
....
}, {
key: 'totalAmount',
label: 'Total',
style:{width: '17%'}
render: (amount, all) => {
console.log(amount);
console.log(all);
return amount + ' ' + currencyToAppend;
}
}
];
While iterating data in table please do the following.
totalAmount.toFixed(2) + " €"
Update:
I would suggest this change should be done from backend, But any how for now you can handle it in map iterator where you are setting orders like following
const currencyToAppend = ' €';
let orders = responseData.map((order) => {
return order.orderStatusChange ? Object.assign({}, order, {
status: order.orderStatusChange[0].status
},{
totalAmount: order.totalAmount.toFixed(2) + currencyToAppend
}) : Object.assign({}, order, {
totalAmount: order.totalAmount.toFixed(2) + currencyToAppend
});
});
I hope this will solve your problem.
To complement #dev's answer, I'd suggest to have render the cell as a function as that gives you more control
Check out the codesandox demo https://codesandbox.io/s/0VVwq645L
const HISTORY_TABLE_COLUMNS = [
{
key: "_id",
label: "Número de pedido",
style: { width: "37%" },
value: item =>
<code>
{item._id}
</code>
},
{
key: "created",
label: "Fecha del pedido",
style: { width: "33%" },
value: item => <Time value={item.created} />
},
{
key: "status",
label: "Estado",
style: { width: "13%" },
value: item =>
<span>
{item.status}
</span>
},
{
key: "totalAmount",
label: "Total",
style: { width: "17%" },
value: item => <Amount value={item.totalAmount} currency="€"} />
}
];

how to get json response from restapi in angularjs using $resource?

This is my angularjs code , I am getting response on console put not able to get it in array or json type form
angular.module('user', ['ngResource']).
config(function($httpProvider){
$httpProvider.defaults.headers.common['Accept'] = "application/json"
})
.factory('loginUser', function($resource){
alert("hello amit we done it");
var user=$resource('http://localhost/testtext/index.php/user/login', {}, {
login: {method:'POST'}}
);
console.log(user.login({"user": {"email":"prashant#gmail.com","password":"weldone"}}));
});
console output
Resource {user: Object, $resolved: false, $then: function, $get: function, $save: function…}
$resolved: true
$then: function (b,g){var j=e(),h=
User: Array[1]
0: Object
address: "Noida"
city: "Mathura"
clientid: "clint000000000000009"
country: "India"
email: "prashant#gmail.com"
flag: "0000000000"
fname: "Sushil"
id: "users000000000000041"
lname: "Kumar1"
password: "ee486c2fa50a03b53982cba45ef045c2"
reset_pw_token: ""
session: Object
auth_token: "a1054379e166a085f4f331074c36b6d7"
created_by: null
created_on: null
id: "usaut000000000000187"
scope: "a:11: {i:0;s:19:"user/changepassword";i:1;s:11:"user/logout";i:2;s:12:"role/getrole";i:3;s:17:"ro le/getprivilege";i:4;s:13:"category/save";i:5;s:13:"message/reply";i:6;s:16:"message/classify";i:7;s:12:"message/read";i:8;s:12:"message/list";i:9;s:12:"tag/messages";i:10;s:8:"tag/l ist";}"
updated_by: null
updated_on: "2013-09-03 19:30:52"
user_id: "users000000000000041"
__proto__: Object
state: "UP"
__proto__: Object
length: 1
__proto__: Array[0]
__proto__: Resource
You need to use the success and failure function
user.login({"user": {"email":"prashant#gmail.com","password":"weldone"}},
function(data){
console.log(data[0]) //or data.User[0] or data.user[0] depending upon on your json.
},
function(error) {
console.log(error) // Error details
})

Categories