After some help here, some online reading, and some headaches, we have managed to get the current time of Rome and updated constantly as if it was in real-time.
Now I am trying to format the way date/time are displayed, but I cannot modify some parameters.
Here is my code:
let timer = setInterval(updateTime, 0);
function updateTime() {
const localeOptions = {
timeZone: 'Europe/Rome',
dateStyle: 'full',
timeStyle: 'short',
formatMatcher: 'day, month, year',
year: '2-digit'
};
const timetag = document.getElementById('timetag');
const url = "https://worldtimeapi.org/api/timezone/Europe/Rome"
fetch(url).then(r => r.json()).then(r => {
const d = new Date(r.datetime);
timetag.innerText = d.toLocaleString('it-IT', localeOptions)
});
}
Everything works until I insert the formatMatcher and the year in 2-digits. I'm following the parameters from here so I wonder what is making everything breaking?
Here the JSFiddle of the timer.
My goal is to have something like 16 APR | 14:06, or at least the closer possible to something minimal in its details and space being taken on screen.
What's wrong in the code, especially in the formatMatcher and year? They break everything ¯_(ツ)_/¯
Can you imagine any problems happening from fetch every 0 milliseconds?
You essentially have the solution, the parts just need to be assembled differently.
The localeOptions is misconfigured -
RangeError: formatMatcher must be either "basic" or "best fit"
TypeError: dateStyle and timeStyle may not be used with other DateTimeFormat options
Fixing that, we have a basic demo -
const f = new Intl.DateTimeFormat("it-IT", {
timeZone: 'Europe/Rome',
dateStyle: 'full',
timeStyle: 'short',
})
console.log(f.format(new Date()))
// lunedì 17 ottobre 2022, 18:08
Parts like fetch are not needed, helping us avoid costly network requests.
Now we can write the setInterval code -
const dtf = new Intl.DateTimeFormat("it-IT", {
timeZone: 'Europe/Rome',
dateStyle: 'full',
timeStyle: 'long',
})
setInterval(() => {
document.body.textContent = dtf.format(new Date())
}, 0)
But setInterval has issues when used in this way. A better option is requestAnimationFrame -
const dtf = new Intl.DateTimeFormat("it-IT", {
timeZone: 'Europe/Rome',
dateStyle: 'full',
timeStyle: 'long',
})
requestAnimationFrame(function update(frame) {
document.body.textContent = dtf.format(new Date())
requestAnimationFrame(update)
})
Related
I want to make clock with useState, useEffect, and setInterval. But when I run this code, "hello" is logged every second. In real code, another code is in place instead of "hello" which I really want to execute only one time. How can I solve this problem?
(Using useEffect is not essential.)
const [clock, setClock] = useState({ year: "", month: "", date: "", hours: "", minutes: "" });
console.log("hello")
useEffect(() => {
const updateEverySecond = setInterval(() => {
setClock(getClock());
}, 1000);
return () => {
clearInterval(updateEverySecond);
};
}, []);
In addition, this is the code of getClock().
function getClock() {
let now = new Date();
var monthArray = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
const year = String(now.getFullYear());
const month = String(monthArray[now.getMonth()]);
const date = String(now.getDate());
const hours = String(now.getHours());
const minutes = String(now.getMinutes()).padStart(2, 0);
return { year, month, date, hours, minutes };
};
You'd actually want to move the code you want to execute only one time into a useEffect hook. Similar to how you're using useEffect now where the code within your current hook executes only once because your dependency array (the second argument of useEffect) is empty. For purposes of code organization, you could simply create a second useEffect hook for whatever would replace console.log("hello"), but regardless of that, the end state would look something like this:
useEffect(() => {
console.log("hello");
}, []);
Yes, In the above code hello will print every time. that is how React functional component works, on every rerender it will execute each line inside the function again, that's why is logging hello
But you can use one another useEffect without any state dependency([]) to achieve the one time call
useEffect(() => {
console.log("hello...");
//this section will only run when component mount (only the first time)
}, []);
here is a full working example
https://codesandbox.io/s/keen-ardinghelli-rmt3l?file=/src/App.js
I am learning react redux, I am using firebase for storing data.
I installed thunk middleware. Everything works, I just don't understand why.
As I understand it, the const expense is an object which is in another function's scope. How can addExpense gets access to it?
export const addExpense = (expense) => ({
type: 'ADD_EXPENSE',
expense
});
export const startAddExpense = (expenseData = {}) => {
return (dispatch) => {
const {
description = '',
note = '',
amount = 0,
createdAt = 0
} = expenseData;
const expense = { description, note, amount, createdAt };
database.ref('expenses').push(expense).then((ref) => {
dispatch(addExpense({
id: ref.key,
...expense
}));
});
};
};
startAddExpense is passing the const expense object to your addExpense function, along with an id field. It just so happens that the argument to addExpense is also called expense, which is where you might be getting confused.
Hope that clears it up.
I am new to cyclejs and rxjs in general and was hoping someone could help me solve my problem.
I am trying to build a demo application for my understanding and stuck with rendering JSON objects on the DOM.
My demo application calls the NASA near earth objects API for the past 7 days and tries to display them.
There is a Load More button at the bottom which on clicking will load data of the previous 7 days (Today - 7 upto Today - 14).
The response I get from the API is as follows
{
"links" : {
"next" : "https://api.nasa.gov/neo/rest/v1/feed?start_date=2016-09-06&end_date=2016-09-12&detailed=false&api_key=DEMO_KEY",
"prev" : "https://api.nasa.gov/neo/rest/v1/feed?start_date=2016-08-25&end_date=2016-08-31&detailed=false&api_key=DEMO_KEY",
"self" : "https://api.nasa.gov/neo/rest/v1/feed?start_date=2016-08-31&end_date=2016-09-06&detailed=false&api_key=DEMO_KEY"
},
"element_count" : 39,
"near_earth_objects" : {
"2016-09-06" : [{
some data
},
{
some data
}],
2016-08-31: [{...}],
...
}
}
I am interested in near_earth_objects JSON object but I am unable to map it beacause of it being an Object.
How do I handle such a situations? Below is the code that I have
function main(sources) {
const api_key = "DEMO_KEY";
const clickEvent$ = sources.DOM.select('.load-more').events('click');
const request$ = clickEvent$.map(() => {
return {
url: "https://api.nasa.gov/neo/rest/v1/feed?start_date=2015-09-06&end_date=2016-09-13&api_key=" + api_key,
method: "GET"
}
}).startWith({
url: "https://api.nasa.gov/neo/rest/v1/feed?start_date=2016-08-31&end_date=2016-09-06&api_key=" + api_key,
method: "GET"
});
const response$$ = sources.HTTP.filter(x$ => x$.url.indexOf("https://api.nasa.gov/neo/rest/v1/feed") != -1).select(response$$);
const response$ = response$$.switch(); //flatten the stream
const nasa$ = response$.map(response => {
return response.body
});
const sinks = {
DOM: nasa$.map(nasa =>
([nasa.near_earth_objects]).map(objects => {
var vdom = [];
//I am not very happy with this part. Can this be improved?
for (var key in objects) {
if (objects.hasOwnProperty(key)) {
vdom.push(objects[key].map(obj => div([
h1(obj.name)
])))
}
}
//returning the vdom does not render on the browser. vdom is an array of arrays. How should i correct this?
console.log(vdom);
return vdom;
})
),
HTTP: request$
};
return sinks;
};
Conceptually, you want to extract the entries of nasa.near_earth_objects (i.e., turn the Object into an Array), then flat map that Array into an Observable sequence.
I'll assume you're already using lodash in your project (you can do it without lodash, but you'll just need to write more glue code manually). I'll also assume you're importing RxJS' Observable as Rx.Observable; adjust the names below to suite your code.
You can accomplish the first task using _.toPairs(nasa.near_earth_objects), and the second part by calling .flatMap(), and returning Rx.Observable.from(near_objects). The resulting Observable will emit items for each key in nasa.near_earth_objects. Each item will be an array, with item[0] being the item's key (e.g., 2016-09-06) and item[1] being the item's value.
Using that idea, you can replace your DOM sink with something like:
nasa$.map(nasa => _.toPairs(nasa.near_earth_objects))
.flatMap(near_objects => Rx.Observable.from(near_objects))
.map(near_object => div([
h1(near_object[1].name)
]))
),
I've been experimenting with feathersjs and angular2/Rx.
What I'm trying to achieve is building an angular2 service that's wrapping a feathersjs service in such a way that one can just subscribe to an Observable that emits an up-to-date set of items after any kind of CRUD.
It basically works. However, I don't find the way it's done very elegant:
Wrapping and unwrapping every object that's coming in doesn't seem efficient. Am I taking 'Everything's a stream' too far?
getService(){
let data$: Observable<any> = Observable.from([initialSetOfItems]);
let created$: Observable<any> = Observable.fromEvent(feathersService, 'created').map(o => {return {action: 'c', data: o}});
let updated$: Observable<any> = Observable.fromEvent(feathersService, 'updated').map(o => {return {action: 'u', data: o}});
let removed$: Observable<any> = Observable.fromEvent(feathersService, 'removed').map(o => {return {action: 'r', data: o}});
return data$
.merge(created$, updated$, removed$)
.scan((arr: any[], newObj) => {
switch (newObj.action){
case 'c':
return [].concat(arr, newObj.data);
case 'u':
let indexToUpdate = arr.findIndex((element) => (element.id === newObj.data.id));
if (indexToUpdate > -1){
arr[indexToUpdate] = newObj.data;
}
return arr;
case 'r':
return arr.filter(element => (element.id != newObj.data.id))
}
});
}
I know this might be opinionated. Please bear with me. Rx is a little hard to wrap your head around.
How would you guys try to achieve this?
I think what you are looking for is exactly what feathers-reactive is supposed to do. It is a plugin that turns any service method into an RxJS observable that automatically updates on real-time events. It can be used like this:
const feathers = require('feathers');
const memory = require('feathers-memory');
const rx = require('feathers-reactive');
const RxJS = require('rxjs');
const app = feathers()
.configure(rx(RxJS))
.use('/messages', memory());
const messages = app.service('messages');
messages.create({
text: 'A test message'
}).then(() => {
// Get a specific message with id 0. Emit the message data once it resolves
// and every time it changes e.g. through an updated or patched event
messages.get(0).subscribe(message => console.log('My message', message));
// Find all messages and emit a new list every time anything changes
messages.find().subscribe(messages => console.log('Message list', messages));
setTimeout(() => {
messages.create({ text: 'Another message' }).then(() =>
setTimeout(() => messages.patch(0, { text: 'Updated message' }), 1000)
);
}, 1000);
});
If you want to give it a try, we would love to get some feedback (and bug reports).
When writing a Mocha test spec against an action creator how can I be certain what a timestamp will be if it is generated within the action creator?
It doesn't have to utilize Sinon, but I tried to make use of Sinon Fake Timers to "freeze time" and just can't seem to get this pieced together wither with my limited knowledge of stubbing and mocking. If this is considered a Redux anti-pattern please point me in a better direction, but my understanding is that Redux action creators can be non-pure functions, unlike reducers.
Borrowing a little from the Redux Writing Tests Recipes here is the core of my problem as I understand it...
CommonUtils.js
import moment from 'moment';
export const getTimestamp = function () {
return moment().format();
};
TodoActions.js
import { getTimestamp } from '../../utils/CommonUtils';
export function addTodo(text) {
return {
type: 'ADD_TODO',
text,
timestamp: getTimestamp() // <-- This is the new property
};
};
TodoActions.spec.js
import expect from 'expect';
import * as actions from '../../actions/TodoActions';
import * as types from '../../constants/ActionTypes';
import { getTimestamp } from '../../utils/CommonUtils';
describe('actions', () => {
it('should create an action to add a todo', () => {
const text = 'Finish docs';
const timestamp = getTimestamp(); // <-- This will often be off by a few milliseconds
const expectedAction = {
type: types.ADD_TODO,
text,
timestamp
};
expect(actions.addTodo(text)).toEqual(expectedAction);
});
});
When testing time I have used this library successfully in the past: https://www.npmjs.com/package/timekeeper
Then in a beforeEach and afterEach you can save the time to be something specific and make your assertions then reset the time to be normal after.
let time;
beforeEach(() => {
time = new Date(1451935054510); // 1/4/16
tk.freeze(time);
});
afterEach(() => {
tk.reset();
});
Now you can make assertions on what time is being returned. Does this make sense?
I would still love to see other answers but I finally got a reasonable solution. This answer uses proxyquire to override/replace the getTimestamp() method defined in CommonUtils when used by TodoActions for the duration of the test.
No modifications to CommonUtils.js or TodoActions.js from above:
TodoActions.spec.js
import expect from 'expect';
import proxyquire from 'proxyquire';
import * as types from '../../constants/ActionTypes';
const now = '2016-01-06T15:30:00-05:00';
const commonStub = {'getTimestamp': () => now};
const actions = proxyquire('../../actions/TodoActions', {
'../../utils/CommonUtils': commonStub
});
describe('actions', () => {
it('should create an action to add a todo', () => {
const text = 'Finish docs';
const timestamp = now; // <-- Use the variable defined above
const expectedAction = {
type: types.ADD_TODO,
text,
timestamp
};
expect(actions.addTodo(text)).toEqual(expectedAction);
});
});