Access data from an array with jquery - javascript

Im trying to loop through an array only i cant seem to extract the data from my array...
http://jsfiddle.net/338Ud/
var listTicker = function (options) {
var defaults = {
list: [],
startIndex: 0,
interval: 3 * 1000,
}
var options = $.extend(defaults, options);
var listTickerInner = function (index) {
if (options.list.length == 0) return;
if (!index || index < 0 || index > options.list.length) index = 0;
var value = options.list[index];
options.trickerPanel.fadeOut(function () {
$(this).html(value).fadeIn();
});
var nextIndex = (index + 1) % options.list.length;
setTimeout(function () {
listTickerInner(nextIndex);
}, options.interval);
};
listTickerInner(options.startIndex);
}
var textlist = new Array({
id: 0,
name: 'Antonia Lallement',
title: '\u003cp\u003e\u003cspan\u003eConsultant\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI started as a resourcer at company three months ago so I\u0026rsquo;m a new team member. Sin...',
image: 'antonia.jpg'
}, {
id: 1,
name: 'Camilla Gobel',
title: '\u003cp\u003e\u003cspan\u003eBusiness Manager\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI joined company in 2011. As a multilingual Consultant, my initial focus was the provisi...',
image: 'camilla.jpg'
}, {
id: 2,
name: 'Mark Dorey',
title: '\u003cp\u003e\u003cspan\u003eDiscipline Manager (Process, Subsea, Project, Safety)\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eWhen I joined company I started as a resourcing specialist and worked across Search and ...',
image: 'mark.jpg'
}, {
id: 3,
name: 'Sadia Butt',
title: '\u003cp\u003e\u003cspan\u003eDiscipline Manager (Mechanical, Piping, Structural)\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI couldn\u0026rsquo;t have asked for a better company to work for! After working as a resourc...',
image: 'sadia.jpg'
}, {
id: 4,
name: 'Samantha Linnert',
title: '\u003cp\u003e\u003cspan\u003ePayroll Assistant\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI began at company as an operations assistant learning to spec CVs and post jobs. Shortl...',
image: 'samantha.jpg'
}, {
id: 5,
name: 'Simon Cottenham',
title: '\u003cp\u003e\u003cspan\u003eConsultant, Middle East\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI have been with company for exactly one year now, I never would have believed that I wo...',
image: 'simon.jpg'
}, {
id: 6,
name: 'Vicky Spencer',
title: '\u003cp\u003e\u003cspan\u003ePayroll Manager\u003c/span\u003e\u003c/p\u003e',
bio: '\u003cp\u003eI started my career at company in July 2012 initially covering maternity leave, managing...',
image: 'vicky.jpg'
});
$(function () {
listTicker({
list: textlist,
startIndex: 0,
trickerPanel: $('.textbox'),
interval: 3 * 1000,
});
});

you are adding object to a html .... use . operator to get the actual values
....
options.trickerPanel.fadeOut(function () {
$(this).html(value.id).fadeIn();
//--------^^^----here
}
i am taking id from the object and showing it in the div.. you can add whatever you need there..
$(this).html(value.title).fadeIn(); //to get title
fiddle here

$.each(textlist, function(index, value){
//do stuff with your array
});

Pasting just the diff, i tried to get the data here below.
From the code above.
options.trickerPanel.fadeOut(function () {
$(this).html(value).fadeIn();
});
The diff,
options.trickerPanel.fadeOut(function () {
$(this).html(value.bio).fadeIn();
});
The difference, is value is the entire array object being passed to the fadeOut function, accessing each elements in the array gives the result.

Related

ES6 reduce function affecting array outside of scope

I've rewritten this into a simplified form to demonstrate, I have an array of pickers who have an array of time entries, I'm using reduce to summarise time entries by type on the pickers & then a second reduce to show global entries across both pickers.
The first reduce per picker works as expected.
The second reduce on global time entries works as expected but somehow changes the entries for the first picker ( Sam ).
Sam & John pick the same amount.
Apples 2h, Peaches 2h, Lemons 1h
Is there a better way to write this? Is there a concept I've failed to understand?
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
summary.push(entry);
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{
id: 1,
identifier: "Sam Smith",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
{
id: 2,
identifier: "John Snow",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
module.exports = testBug;
Even though with each reducer you pass a new array [], the actual objects contained by these arrays could be shared. This means when you edit one of the objects in array "A", the objects could also change in array "B".
You know how some languages let you pass variables by value or by reference and how this fundamentally changes how values are handled? JavaScript technically uses call-by-sharing. I suggest reading this other answer: Is JavaScript a pass-by-reference or pass-by-value language?
once an element in an array is pushed into a different array it is separate in memory?
No, it isn't. In JavaScript you will always remember when you made an individual copy of an object (or at least wanted to), because that needs some effort, see What is the most efficient way to deep clone an object in JavaScript? or How do I correctly clone a JavaScript object?
So, just like when you use a=b, push(a) into an array refers the original object. See this example where there is a single object accessible via two variables (x and y), and via both elements of array z. So modifying it as z[1] affects all the others:
let x={a:5};
let y=x;
let z=[x];
z.push(y);
z[1].a=4;
console.log(x);
console.log(y);
console.log(z[0]);
console.log(z[1]);
As your objects are value-like ones and do not have anything what JSON would not support (like member functions), JSON-based cloning can work on them:
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
//summary.push(entry);
summary.push(JSON.parse(JSON.stringify(entry))); // <--- the only change
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{id: 1, identifier: "Sam Smith", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},
{id: 2, identifier: "John Snow", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
Now it probably displays what you expected, but in the background it still alters the pickers themselves, you have that picker.timeEntries = ... line running after all. It may be worth mentioning that const something = xy; means that you can not write something = yz; later, something will stick with a given entity. But, if that entity is an object, its internals can still be changed, that happens with picker.timeEntries above (while writing picker = 123; would fail).

Load all data from local database

I am using react-native-gifted-chat(https://github.com/FaridSafi/react-native-gifted-chat) to create a chat interface on my app, I want to load messages from my database.
I am using realm, and I am able to load the data but my code below loads only the first row of the data. I want to be able to load all the data from the database.
let chatData = realmDatabase.objects(DatabaseTableNames.chatTable);
let data=[];
for (let message of chatData ){
data = [{
_id: message.chatUniqueID,
text: message.msgBody,
createdAt: (new Date()).getTime(),
user: {
_id: message.chatUniqueID,
name: message.senderName
}
} ]
}
console.log(data)
I want to be able to load all the data from the database not only the first row, like the sample below.
[
{
_id: Math.round(Math.random() * 1000000),
text:
"It uses the same design as React, letting you compose a rich mobile UI from declarative components https://facebook.github.io/react-native/",
createdAt: new Date(Date.UTC(2016, 7, 31, 17, 20, 0)),
user: {
_id: 1,
name: "Developer"
},
},
{
_id: Math.round(Math.random() * 1000000),
text: "React Native lets you build mobile apps using only JavaScript",
createdAt: new Date(Date.UTC(2016, 7, 30, 17, 20, 0)),
sent: true,
received: true,
user: {
_id: 2,
name: "Developer"
},
}
];
Doing data = [{...}] in the for loop, will assign the last value of message to data. To get all the values, you need to push the items in the data array. You can do it like this:
let chatData = realmDatabase.objects(DatabaseTableNames.chatTable);
let data=[];
for (let message of chatData ){
data.push({
_id: message.chatUniqueID,
text: message.msgBody,
createdAt: (new Date()).getTime(),
user: {
_id: message.chatUniqueID,
name: message.senderName
}
});
}
console.log(data)

How to create a json grouped by date in js?

I have an array of objects sorted by date:
const alerts = [{
id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1'
}, {
id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one'
}]
I am trying to 'group' the alerts by date so trying to create 'datesections' which have a dateheader, the result should be something like:
const sections = [{
date: '2018-10-31T23:18:31.000Z',
heading: 'today',
alerts: [{ id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke',
title: 'this is the first one' }]
}, {
date: '2018-10-30T23:18:31.000Z',
heading: 'Yesterday',
alerts: [{ id: 2, date: '2018-05-30T23:18:31.000Z', name: 'Mark',
title: 'this is the second one' }]
}]
I tried something this but can't figure out how to get the alerts with the same date in the alerts prop:
const sections2=alerts.map(a =>
({
date: a.date,
heading:'today new',
alerts:alerts
})
)
const alerts = [
{ id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
{ id: 2, date: '2018-05-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' }
]
const grouping = _.groupBy(alerts, element => element.date.substring(0, 10))
const sections = _.map(grouping, (items, date) => ({
date: date,
alerts: items
}));
console.log(sections);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Can't help you with headings - what if it's neither "today" or "yesterday"?
I feel like you are asking a couple of things here. The key one is how to group by day with a date.
To do that you will first need to know how to group. This answer may help with that.
As far as how to group by day there are a number of ways to do that. Simplest I can think of is to cut off everything after the "T" in the date string and sort that.
From my point of view it's not really a map what you need here, map will return a new array but not what you want. You can do this with 2 for statements
let total = [];
for (let j = 0; j < alerts.length; j++) {
let item = alerts[j];
let foundDate = false;
for (let i = 0; i < total.length; i++) {
if (total[i].date === item.date) {
foundDate = true;
total.alerts.push(item);
}
}
if (!foundDate) {
console.log("!found");
total.push({
date: item.date,
heading: "Yesterday",
alerts: [item]
});
}
}
If you console.log yout total array, will contain what you want.
If you need any other explanation pls let me know.
You can use a regular expression to match the part of the date you want and then group your data. You can add there the header you want. Hope this helps.
const alerts = [
{ id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
{ id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' },
{ id: 3, date: '2018-10-30T23:14:32.000Z', name: 'Mark', title: 'this is the third one' }
];
const groupByDate = (data) => {
return data.reduce((acc, val) => {
const date = val.date.match(/\d{4}-\d{2}-\d{2}/g).toString();
const item = acc.find((item) => item.date.match(new RegExp(date, 'g')));
if (!item) acc.push({ date: val.date, alerts: [val], heading: 'some heading' });
else item.alerts.push(val);
return acc;
}, []);
};
console.log(groupByDate(alerts));
Maybe you need something like this? Didn't have much time for this and last array parsing might be done in more elegant way ;)
var alerts = [
{ id: 1, date: '2018-10-31T23:18:31.000Z', name: 'Joke', title: 'this is the first 1' },
{ id: 3, date: '2018-10-31T23:44:31.000Z', name: 'Joke1', title: 'this is the 2nd' },
{ id: 2, date: '2018-10-30T23:18:31.000Z', name: 'Mark', title: 'this is the second one' },
{ id: 4, date: '2018-10-30T23:45:31.000Z', name: 'Mark1', title: 'this is the 3rd' },
{ id: 5, date: '2018-10-27T23:18:31.000Z', name: 'Mark2', title: 'this is the 4th' },
];
var processedAlerts = [], finalAlerts;
(function(initAlerts){
//iterate through array to make keys to group by day
for(var i = 0; i < initAlerts.length; i++){
processedAlerts[i] = initAlerts[i];
//substring here can be more sophisticated - this was faster
initAlerts[i].keyDate = initAlerts[i].date.substr(0, 10);
}
//supporting function to convert string to date
//to acheve more detailed sorting that includes time
//just use date object and use hours, minutes and/or seconds to create Date object
function dateFromString(strDate){
var date, tmpDate;
//convert string to array - I assume that date format is always the same
//yyyy-mm-dd and will become Array 0: year, 1: month, 2: day of the month
tmpDate = strDate.split("-");
//moths in js are zero pased so Jan is 0, Feb is 1 and so on
//so we want to substract 1 from human readable month value to get correct date
date = new Date(tmpDate[0], tmpDate[1]-1, tmpDate[2]);
return date;
}
//function used to compare dates and passed to sort function
function comparedates(obj1, obj2){
var date1, date2;
date1 = dateFromString(obj1.keyDate);
date2 = dateFromString(obj2.keyDate);
let comparison = 0;
if(date1>date2){
comparison = 1;
} else if(date1<date2){
comparison = -1;
}
//to achieve reverse just multiply comparison result by -1
return comparison*(-1);
}
function getHeader(date){
//here place logic to generate header
//this involves comparing dates probably from keyDate
return "temp header: " + date.toString()
}
//sort the array by keyDate from newest to oldest
processedAlerts.sort(comparedates);
//final array rebuild
//pass here sorted array
finalAlerts = (function(arrayAlerts){
var aAlerts = [], k = 0;
for(var j = 0; j < arrayAlerts.length; j++){
//check if entry for date exists
//if no than create it
if(!aAlerts[k]){
aAlerts[k] = {
//removed title because I asummed that each alert has unique title and put them in alerts instead
date: arrayAlerts[j].keyDate, //agroupped date
heading: getHeader(arrayAlerts[j].keyDate), //update this function to return personalized heading
//here you can shape the alert object how you need
//I just passed it as it was
alerts: [arrayAlerts[j]] //array with first object inside
};
} else {
//add another alert to day
aAlerts[k].alerts.push(arrayAlerts[j]) //array with first object inside
}
//increasing final array key
//if there is previous entry and keys are the same for current and previous
if(arrayAlerts[j-1] && (arrayAlerts[j].keyDate == arrayAlerts[j-1].keyDate)){
k++;
}
}
return aAlerts;
})(processedAlerts);
})(alerts);
console.log(finalAlerts);

How do i search 'titles' from array of objects & return only objects that match searchTerm?

bit of a newbie! I am trying to re-populate a carousel of images... based on an array of search results. But really hitting surprising amount of issues.
I'm using JS/Jquery and have, say, an array of objects that exist from my api:
let arrayOfObjects = [
{id: 0, title: 'Beauty & The Beast', img: 'https://imgthing1.com' },
{id: 1, title: 'The Brainiac', img: 'https://imgthing2.com' },
{id: 2, title: 'Mac and Me', img: 'https://imgthing3.com' }
];
Then i have my searchTerm which i want to filter the array down, and return a new array of results from:-
function checkWords(searchTerm, arr) {
let results = [];
let st = searchTerm.toLowerCase();
// **** i map through the array - if the search term (say its 'a' is the same
// as the first character of an object's 'title'... then it stores
// that object in results, ready to be rendered. ****
arr.map((each) => {
if (st === each.title.charAt(0)) {
results.push(each)
}
})
console.log(finalResults);
}
But i can't work out how to keep it matching... based on:
'Bea' vs 'Beauty & The Beast' - pass.
'Beat' vs 'Beauty & The Beast' - fail.
You could use Array#filter and check if the string contains the wanted string at position zero.
let arrayOfObjects = [{ id: 0, title: 'Beauty & The Beast', img: 'https://imgthing1.com' }, { id: 1, title: 'The Brainiac', img: 'https://imgthing2.com' }, { id: 2, title: 'Mac and Me', img: 'https://imgthing3.com' }];
function checkWords(searchTerm, arr) {
let st = searchTerm.toLowerCase();
return arr.filter(each => each.title.toLowerCase().indexOf(st) === 0);
}
console.log(checkWords('bea', arrayOfObjects));

Create randomly generated divs that fill a box jQuery and Javascript

I have a section on my website that is 100% wide and 450 pixels tall.
My html looks like so...
<section class="interactive-banner">
<figure></figure>
</section>
I want each 'figure' element to be 150 pixels wide and 150 pixels tall, I want to generate the 'figure' html automatically and randomly with jQuery, and to consist of some inner html.
I have the following...
$(function(){
var people = [
{ id: 1 },
{ id: 2 }
];
var figure = $('figure');
w = 1500;
h = 450;
var counter = 0;
var data = people[Math.floor(Math.random()*people.length)];
(function nextFade() {
counter++;
figure.clone().html(data.name).appendTo('.interactive-banner').hide().fadeIn(150, function() {
if(counter < 30) nextFade();
});
})();
});
I want each figure element to fade in 1 after the other, in total I will only have 7 original figures, only these 7 will be randomly cloned until i have 30 iterations in total, I want the figure html to contain the data inside each object in my people array, so each figure is an object so to speak, output as so...
<figure>
<img src="[image src from object inside array]" />
<div class="information">
<h5>[name from object inside of array ]</h5>
<p>[job title from object inside of array ]</p>
</div>
</figure>
only at the minute its being output as so...
<figure style="display: block;">
Chris
</figure>
Ive created an example here, as you see however each figure contains the same information...
http://jsfiddle.net/pGmeE/
http://jsbin.com/isopin/1/edit
Don't populate your section initially and don't clone your figure element with jQ. Rather create a new one at every loop iteration.
<section class="interactive-banner"></section>
jQ:
$(function(){
var people = [
{ id: 1, name: 'Justin', title: 'Head Designer', bio: 'This is Justin\'s Biography.', image: 'justin.jpg' },
{ id: 2, name: 'Chris', title: 'Head Developer', bio: 'This is Chris\' Biography.', image: 'chris.jpg' },
{ id: 3, name: 'Sam', title: 'Developer', bio: 'This is Sam\'s Biography.', image: 'sam.jpg' },
{ id: 4, name: 'Haythem', title: 'Developer', bio: 'This is Haythem\'s Biography.', image: 'haythem.jpg' },
{ id: 5, name: 'Geoff', title: 'Designer', bio: 'This is Geoff\'s Biography.', image: 'geoff.jpg' },
{ id: 6, name: 'Liam', title: 'Designer', bio: 'This is Liam\'s Biography.', image: 'liam.jpg' }
];
w = 1500;
h = 450;
var counter = 0;
(function nextFade() {
counter++;
// Give "random" a chance to get random again
var data = people[Math.floor(Math.random()*people.length)];
// Now create a new Figure element:
var figure = $('<figure />');
figure.html(data.name).appendTo('.interactive-banner').hide().fadeIn(150, function() {
if(counter < 30) nextFade();
});
})();
});

Categories

Resources