I want to check an Array until it's filled and show up a loading dialog but it always tells me
this.events[0] is undefined
ngOnInit() {
this.initMethod();
if(this.events[0].start == this.books[0].date_from_og) {
this.dialog.closeAll();
}
}
But events cant be undefined because it contains event of a calendar which get displayed.
initMethod() {
this.service
.getEmployees()
.subscribe(
(listBooks) => {
this.books = listBooks;
this.events = this.books.map((book) => {
return {
start: new Date(book.date_from_og),
end: new Date(book.date_to_og),
type: ""+book.type,
title: "" + book.device + "",
color: colors.blue,
actions: this.actions,
resizable: {
beforeStart: false,
afterEnd: false
},
draggable: false
}
});
},
(err) => console.log(err)
);
}
}
And Constructor:
constructor(private modal: NgbModal, private service: BookingService, private dialog: MatDialog) {
this.initMethod();
this.dialog.open(DialogLaedt, {
width: '650px'
});
Your issue is that you initMethod() retrieves the result asynchronously.
So when you reach the line with if(this.events[0].start == ... there is no guarantee that the event data has been retrieved from the service yet.
The fix is to move your check inside the subscribe part of your init method (which executes as soon as the observable emits it's value), or let the init method return an observable that you can subscribe to, and perform your check inside that subscription.
Solution 1 - Moving your check inside subscription
ngOnInit() {
this.initMethod();
}
initMethod() {
this.service
.getEmployees()
.subscribe(
(listBooks) => {
this.books = listBooks;
this.events = this.books.map((book) => {
return {
start: new Date(book.date_from_og),
end: new Date(book.date_to_og),
type: ""+book.type,
title: "" + book.device + "",
color: colors.blue,
actions: this.actions,
resizable: {
beforeStart: false,
afterEnd: false
},
draggable: false
}
if(this.events[0].start == this.books[0].date_from_og) {
this.dialog.closeAll();
}
});
},
(err) => console.log(err)
);
}
Solution 2 - Letting your initMethod return an Observable
ngOnInit() {
this.initMethod().subscribe(() => {
if(this.events[0].start == this.books[0].date_from_og) {
this.dialog.closeAll();
}
});
}
initMethod() {
return this.service
.getEmployees()
.pipe(tap(
(listBooks) => {
this.books = listBooks;
this.events = this.books.map((book) => {
return {
start: new Date(book.date_from_og),
end: new Date(book.date_to_og),
type: ""+book.type,
title: "" + book.device + "",
color: colors.blue,
actions: this.actions,
resizable: {
beforeStart: false,
afterEnd: false
},
draggable: false
}
});
}))
}
I have noticed that you are calling the initMethod() twice. Once in the constructor, and once in the ngOninit method.
Related
I'm using the tinyMCE editor in my React project. I need a custom button based on number of additional users. If it has 3 additional users, I add 3 additional buttons in my dropdown.
import { Editor } from '#tinymce/tinymce-react';
...
const [ totalAdditionalUsers, setTotalAdditionalUsers] = useState(0);
// I get this data from NodeJS backend and set the value inside my useEffect
// I'll simplify the code here
useEffect(() => {
setTotalAdditionalUsers(myVariable); // The value here is 3, for example
});
console.log(totalAdditionalUsers); // it shows 3
return (
<>
<Editor
apiKey={TINYMCEKEY}
value={editorContent}
init={{
height: 600,
menubar: false,
branding: false,
plugins: [
"print"
],
setup: function (editor) {
editor.ui.registry.addMenuButton('addAllSignatures', {
text: "Users Signature",
fetch: function (callback) {
var items = [
{
type: 'menuitem',
text: 'Primary User Signature',
onAction: function () {
editor.insertContent(' <strong>#userSignature#</strong> ');
}
}, {
type: 'menuitem',
text: 'Primary User Signature Date',
onAction: function () {
editor.insertContent(' <strong>#userSignatureDate#</strong> ');
}
}
];
console.log(totalAdditionalUsers); // It is showing 0. Why??
for(let i=1; i<=totalAdditionalUsers; i++) {
let s = 'th';
if(i === 1) s = 'nd';
else if(i === 2) s = 'th';
const objSign = {
type: 'menuitem',
text: `${(i+1)}${s}User Signature`,
onAction: function () {
editor.insertContent(` <strong>#addUser${i}#</strong> `);
}
};
const objDate = {
type: 'menuitem',
text: `${(i+1)}${s}User Signature Date`,
onAction: function () {
editor.insertContent(` <strong>#addUser${i}SignatureDate#</strong> `);
}
};
items.push(objSign);
items.push(objDate);
}
callback(items);
}
})
},
toolbar1: "print | addAllSignatures"
}}
onEditorChange={handleEditorChange}
/>
</>
);
My issue, it that inside the TinyMCE editor, the totalAdditionalUsers is always 0. Looks like it is not updating.
Am I setting in wrong?
Thanks
Am new in Angular technology and working with Angular with spring boot as back end. Am stuck in reloading data gird.i have a backed API call for populating data gird. My issue was like some time data will change in the response.based on this I need to update my data grid in UI.
Edit 1
Angular.ts file
#ViewChild('modal', { static: false }) modal;
columns = [
{
prop: 'Name',
name: 'name'
},
{
prop: 'Location',
name: 'Location'
},
{
prop: 'Status',
name: 'Status'
}
];
ngOnInit() {
}
getData(name): Observable<Nodes> {
return this.service.getData(name).pipe(map((data) => {
return data;
}));
}
loadInitialData() {
this.getData(this.name).subscribe((data) => {
this.dataFrom = data;
this.service.saveMessage(data);
data.dataNodes.forEach((elm) => {
if (elm.archiveGroups === null) {
return;
}
elm.archiveGroups.forEach(arch => {
if (arch.archives === null) {
return;
}
let row: rowJson;
arch.archives.forEach(arc => {
row = Object.assign(new rowJson(), {
Name: arc.Name,
Location: elm.NodeName,
Status: arc.status,
});
this.rows.push(row)
});
});
});
this.loadingState = false;
this.populateData();
}, err => {
});
}
Edit 2
I have done below changes in ngOnInit method.but status filed not updated
ngOnInit() {
this.updateSubscription = interval(1000).subscribe(
(val) => {
this.getData(this.hostname).subscribe((data) => {
data.dataNodes.forEach((elm) => {
elm.archiveGroups.forEach(arch => {
if (arch.archives === null) {
return;
}
arch.archives.forEach(arc => {
let row: rowJson;
row.Status=arc.status
});
});
});
});
}
);
}
How to update status field based on getData API response.I could see a lot of queries regarding reload. Please guide and suggest a valid Solution
My goal is to display events I get from firestore using ng-fullcalendar.
But the problem is, it doesn't show up in the calendar.
If used mock data it works, but on data I got from firestore doesn't
So here's the working calendar with mock data
The function
public getEvents(): Observable<any> {
const dateObj = new Date();
const yearMonth = dateObj.getUTCFullYear() + '-' + (dateObj.getUTCMonth() + 1);
let data: any = [{
title: 'namee',
start: '2018-09-19'
},
{
title: 'STI night',
start: '2018-09-18'
}
];
console.log(data);
return of(data);
}
What displays in the console.log
And how I init the calendar with the event
ngOnInit() {
this.getEvents().subscribe(eventData => {
console.log('Obs', eventData);
this.calendarOptions = {
editable: true,
eventLimit: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listMonth'
},
events: eventData
};
});
}
The log on observable
But when I do this, the function that gets data from firestore
getEventsCollection(): Observable<any>{
this.eventService.getEventsCollection().subscribe(eventCollection => {
eventCollection.forEach(event => {
this.fullCalendarEvent = {
title: event.event_name,
start: event.event_date
}
this.eventsArray.push(this.fullCalendarEvent);
})
});
console.log( this.eventsArray );
return of(this.eventsArray);
}
Which logs this
When I replace the function
ngOnInit() {
this.getEventsCollection().subscribe(eventData => {
console.log('Obs', eventData);
this.calendarOptions = {
editable: true,
eventLimit: false,
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay,listMonth'
},
events: eventData
};
});
}
But it doesn't show up in the calendar
Maaaan, my head hurts. Any tips on how to display them would be greatly apreciated!
UPDATE
Now I see the difference,
the mock data is this [{…}, {…}] (a what might be an object)
while mine is [] an array
Anyone knows how I can do so?
It was the lifecycle hook all along!
When I put the init calendar in counstructor, voila,it worked!
Below is a function getting messages from firebase database, but it only setState to only one message.
However, the console.log can log multiple messages in the object.
Is there anything wrong in my function?
getMessages(){
var messages = [];
firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
//alert(JSON.stringify(dataSnapshot.val()));
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{
//alert(JSON.stringify(messages));
messages.push({
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
});
this.setState({
messages: messages
});
console.log('woooo'+JSON.stringify(messages));
});
});
});
}
You are setting the state inside the forEach Block. try moving it outside the iteration block
As JanneKlouman mentioned it's not good enough to remove it from the iterration block as you are doing async calls.
You can create a new array and set it in the state on each iteration, react will batch those set state calls:
function getMessages() {
var messages = [];
firebaseApp.database().ref('users/' + firebase.auth().currentUser.uid + '/userChat/' + firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
//alert(JSON.stringify(dataSnapshot.val()));
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message) => {
const newMessage = {
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
}
const nextState = this.state.messages.map(message => {
return {
...message,
user: {...meesage.user} // i think we must do this in order to break out of the reference as spreading will only work on a shallow level
}
});
this.setState({
messages: [...nextState, newMessage]
});
});
});
});
}
Try cloning the array before setting state:
getMessages(){
let messages = [];
firebaseApp.database().ref('users/'+firebase.auth().currentUser.uid+'/userChat/'+firebase.auth().currentUser.uid).orderByValue().limitToLast(10).once('value', (dataSnapshot) => {
dataSnapshot.forEach((child) => {
firebaseApp.database().ref('messages').child(child.key).once("value", (message)=>{
const message = {
_id: Math.round(Math.random() * 1000000),
text: message.val().text,
createdAt: new Date(message.val().timestamp),
user: {
_id: 1,
name: 'Developer',
},
};
// Clone messages
messages = [...messages, message];
this.setState({ messages });
});
});
});
}
i have some actions in reflux actions, this is my actions
var BeritaActions = Reflux.createActions({
'getListBerita': {
children: [
'actions', 'completed', 'failed'
]
},
'getBerita': {
children: [
'actions', 'completed', 'failed'
]
},
});
BeritaActions.getListBerita.listen(function(param)
{
return BeritaUtil.listBerita(param)
.on('error', this.failed)
.end(this.completed);
});
BeritaActions.getBerita.listenAndPromise(function(id)
{
return BeritaUtil.read(id)
.on('error', this.failed)
.end(this.completed);
});
this is my store, and listen to actions
Reflux.createStore({
onprogress: false,
type: null,
init()
{
this.listenTo(BeritaAct.getListBerita.completed, this.getInitData);
this.listenTo(BeritaAct.getListBerita.failed, this.getInitErrorData);
},
setType(type)
{
return this.type = type;
},
getCurrentData()
{
return _data;
},
getInitData(field)
{
console.log(field)
let data = JSON.parse(field.text);
if(data.meta.code == 200)
{
if(typeof _data[this.type] == 'undefined')//first open
{
//console.log('first')
_data[this.type] = data.data;
}else//on load more = merging data
{
//console.log(_data[this.type])
_data[this.type] = update(_data[this.type], {$merge: data.data});
}
this.trigger(_data);
}else
{
Toas.error({title:data.meta.message, content:''});
}
},...
so i execute actions in my components
React.createClass({
getInitialState()
{
if(Progress.isAjax())
{
Progress.onProgress(true);
BeritaStore.setType('list');
BeritaAct.getListBerita({});
}else
{
//not ajax
}
return {
showloader: {display: 'none'},
shownext: {display: 'block'}
};
},..
store can listen actions so well and can return on my react component. but when i check network inspect, i got the action request many time, i don't know what happening ?
ok guys i solved that problem, let going to getInitData function
getInitData(bind, field)
{
console.log(field)
}
i add parameter on getInitData function, so after i console.log() second paramater, i get the data