Angular 2 periodically pull real time data - html

I have developed an app which basically has admin and client portal running in separate ports and when an order is placed from client side, the admin dashboard should be able to get the new order shown.
Basically the view has to be refreshed to keep an updated UI.
For which i have referred the below link:
http://beyondscheme.com/2016/angular2-discussion-portal
Below is what i have tried.
order-issue.component.ts
ngOnInit() {
const user_id = {
user_ids: this.user_id
};
// To display the Pending Orders into the table
this.orderService.getAllOrders("Pending").subscribe(data => {
if (data.success && data.Allorders.length != 0) {
for (let i = 0; i < data.Allorders.length; i++) {
this.orderService
.getOrderItemsByNo(data.Allorders[i].orderNo)
.subscribe(subData => {
data.Allorders[i].orderItems = subData;
});
}
this.source = data.Allorders; //To display the data into smart table
this.refreshData(); //For real time refresh
} else {
this.flashMessage.show("No Pending Orders", {
cssClass: "alert-success",
timeout: 300000
});
}
});
private refreshData(): void {
this.commentsSubscription = this.orderService.getAllOrders("Pending").subscribe(data => {
this.data = data;
console.log(data); //able to see the new orders
this.subscribeToData();
});
private subscribeToData(): void {
this.timerSubscription = Observable.timer(5000).first().subscribe(() => this.refreshData());
}
My service(orderService) will get all the orders:
getAllOrders(status) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post(`${BASE_URL}/orders/getAllOrdersWithItems`, { status: status }, { headers: headers })
.map(res => res.json());
}

Ok i am able to fix it with below change.
//Function which refreshes the data in real time without page refresh
private refreshData(): void {
this.commentsSubscription = this.orderService.getAllOrders("Pending").subscribe(data => {
this.source = data.Allorders; //Updated here! and it worked
console.log(this.source);
this.subscribeToData(); //On success we call subscribeToData()
});
}

Related

Angular how to push nested reactive form json ids in formArray

I want to submit an album gallery with eventTitle and multiple images. I am able to upload multiple images with eventTitle. It might be silly ask but I am new in angular and this is my first project on this. Stuck with this problem. Any reference/document would a big help.
While submitting the form, I just need to pass array of ids of images and eventTitle. My json looks like below:
{
"eventTitle": "Event to be celebrate - Happy New Year..!!",
"image": [
{
"id": 1
},
{
"id": 2
},
{
"id": 3
}
]
}
Problem is here that I am not able to push the array of ids. Only last uploaded image's id is getting push. notable to loop the ids and push into formArray. Can someone please help me how can loop the ids of all uploaded images?
// my Gallery component ts file:
constructor(private fb: FormBuilder,
private http: HttpClient,
private gallaryService: GallaryService,
private fileService: FileService,
private renderer: Renderer2) {
this.gallaryForm = this.fb.group({
eventTitle: [''],
image: this.fb.array([])
});
this.addGallaryImages();
}
ngOnInit() {
}
initSocialProfiles() {
return this.fb.group({
id: ['']
});
}
addGallaryImages() {
const control = this.gallaryForm.controls.image as FormArray; // how to loop it ids of array
const addrCtrl = this.initSocialProfiles();
control.push(addrCtrl);
console.log(addrCtrl);
}
gallaryFormSubmit() { //submitting the form
if (this.gallaryForm.valid) {
const gallaryFormData = this.gallaryForm.value;
gallaryFormData.image = [];
gallaryFormData.image[0] = {};
gallaryFormData.image[0].id = this.imageId;
this.gallaryService.saveGallaryForm(gallaryFormData).subscribe((response) => {
console.log(response);
// this.dialog.closeAll();
alert('New Gallary has been added...!');
});
}
}
onSelectedFile(event){
if (event.target.files.length > 0){
const image = event.target.files[0];
const formData = new FormData();
formData.append('file', image);
this.fileService.saveFile(formData).subscribe(
res => {
console.log(res);
if (res){
this.uploadError = '';
this.imageId = res.id;
const li: HTMLLIElement = this.renderer.createElement('li');
const img: HTMLImageElement = this.renderer.createElement('img');
img.src = res.path;
this.renderer.addClass(img, 'image');
const a: HTMLAnchorElement = this.renderer.createElement('a');
a.innerText = 'Remove';
this.renderer.addClass(a, 'delete-btn');
// a.addEventListener('click', this.deleteProductImage.bind(this, res.response.filename, a));
this.renderer.appendChild(this.image.nativeElement, li);
this.renderer.appendChild(li, img);
this.renderer.appendChild(li, a);
}
else {
this.uploadError = res.massage;
}
},
err => this.error = err
);
}
}
Gallery Service:
saveGallaryForm(gallary){
return this.http.post<any>('http://localhost:8080/gallary/save', gallary)
.pipe(
retry(1),
catchError(this.errorHandl)
);
}
[![ In below console log, last uploaded image id is getting push. I need all uploaded image ids in this array.][1]][1]

Object from Observable then Array from Observable inside a foreach. how to order it?Asynchronous Angular 4/5

Here is my problem.
I'm running a method that sends me a json (method = myTableService.getAllTables ()), to create an object (object = this.myTables).
Then I execute the method for each, for each element of this.myTables I execute a new request (request = this.myTableService.getTableStatut (element.theId)).
I retrieve data from a new json to create an object (object = myTableModel).
Each result will be added to this.myTableListProvisory.
The problem is the order of execution.
It execute the console.log before the end of the for each...
This.myTableListProvisory.length and this.myTableList.length return 0.
How to wait for the end of the for each run before running the console.log?
Thank you
ngOnInit() {
this.myTableService.getAllTables()
.subscribe(data => {
this.myTables = data;
this.myTableList = this.getAllTableStatut(this.myTables);
console.log("this.myTableList.length : " + this.myTableList.length);
}, err => {
console.log(err);
})
}
getAllTableStatut(myTables: any) {
this.myTableListProvisoire = [];
myTables.forEach(element => {
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
})
console.log("this.myTableListProvisoire.length : " + this.myTableListProvisoire.length);
})
return this.myTableListProvisoire;
}
Result of console.log
this.myTableListProvisoire.length : 0
this.myTableList.length : 0
UPDATE
I have simplified the code ... I put it in its entirety for the understanding. What I need is to sort the array after it is done. The problem is that I don't know how to use a flatMap method in a query inside a foreach ... I have temporarily placed the sort method inside the subscribe which is a bad solution for the performance. That's why I want to do my sort after the creation of the array. Thank you
export class MyTableComponent implements OnInit {
myTables: any;
statut: any;
myTableModel: MyTableModel;
myTableList: Array<MyTableModel>;
myTableListProvisoire: Array<MyTableModel>;
i: number;
j: number;
myTableModelProvisoire: MyTableModel = null;
constructor(public myTableService: MyTableService) { }
ngOnInit() {
this.myTableService.getAllTables()
.subscribe(data => {
this.myTables = data;
this.myTableList = this.getAllTableStatut(this.myTables);
}, err => {
console.log(err);
})
}
getAllTableStatut(myTables: any) {
this.myTableListProvisoire = [];
myTables.forEach(element => {
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
for (this.j = 0; this.j < this.myTableListProvisoire.length; this.j++) {
for (this.i = 0; this.i < this.myTableListProvisoire.length - 1; this.i++) {
if (this.myTableListProvisoire[this.i].getTableNumber() > this.myTableListProvisoire[(this.i + 1)].getTableNumber()) {
this.myTableModelProvisoire = this.myTableListProvisoire[this.i];
this.myTableListProvisoire[this.i] = this.myTableListProvisoire[(this.i + 1)];
this.myTableListProvisoire[(this.i + 1)] = this.myTableModelProvisoire;
}
}
}
}, err => {
console.log(err);
})
}, err => {
console.log(err);
})
return this.myTableListProvisoire;
}
}
Well Observables are asynchronous actions and will be executed after finishing the current execution block. So when the js engine comes to your
this.myTableService.getTableStatut(element.theId)
.subscribe(data => {
this.statut = data;
this.myTableModel = new MyTableModel(element.tableNumber, this.statut.name, element.theId);
this.myTableListProvisoire.push(this.myTableModel);
})
it will only create a subscription, but the code inside of it will be executed after all the other code in the block. So that's why your console.log is being executed before you get any data. So you need to place it inside the .subscribe block to see the. I think there can be a better solution to get the data, but I don't know the structure of the app, so I can't advice. If you create an example on https://stackblitz.com/ I could probably help you out with a better solution.

Pushing complete data from Spring Boot server through Web Socket to Client

I have a spring boot server and i am able to generate a streaming table on client side by sending json one after the another. The problem is if a user logs in say after 10 minutes, he is only able to access data starting from 10th minute i.e he is not able to access data from 0 to 10th minute. What i want is to push the data from 0th to 10th minute first and at the same time continue the streaming process. How can this be done? I am using jquery datatable to generate the table.
I am attaching the controller and client side html for reference
1) Controller
#Controller
public class ScheduledUpdatesOnTopic {
#Autowired
private SimpMessagingTemplate template;
int count=0;
#Scheduled(fixedDelay=500)
public void trigger() {
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String str[] = {"name"+count,""+Math.round(Math.random()*100),"India"+Math.round(Math.random()*100),df.format(date)};
this.template.convertAndSend("/topic/message",str);
++count;
}
}
2) Client HTML
var _self = this;
$(document).ready(function() {
var message ;
$('#tbl').DataTable( {
data: message,
"aLengthMenu" : [[25,50,75,-1],[25,50,75,"All"]],
"pageLength" :25,
columns: [
{ title: "Name" },
{ title: "Age" },
{ title: "Country" },
{ title: "Date"}
]
});
subscribeSocket();
});
function addRow(message){
var table = $('#tbl').DataTable();
if(table && message ){
table.row.add(message).draw();
}
}
function subscribeSocket(){
var socket = new SockJS('/gs-guide-websocket');
var stompClient = Stomp.over(socket);
stompClient.connect({ }, function(frame) {
stompClient.subscribe("/topic/message", function(data) {
message = JSON.parse(data.body);
_self.addRow(message);
});
});
};
If you don't save previous sent datas, you can't send them back to new customers.
On the front side, you have to subscribe to an "history" resource and make a call to get it.
Front:
function subscribeSocket() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
var firstCounterReceived = null;
stompClient.connect({}, function (frame) {
setConnected(true);
stompClient.subscribe('/topic/history', function (response) {
console.log(JSON.parse(response.body));
});
stompClient.subscribe('/topic/message', function (response) {
var message = JSON.parse(response.body);
if (firstCounterReceived == null) {
firstCounterReceived = message[0];
console.log(`Calling history endpoint with ${firstCounterReceived}`);
stompClient.send("/app/topic/history", {}, message[0]);
}
console.log(message);
});
});
}
Back:
#Controller
#EnableScheduling
public class ScheduledUpdatesOnTopic {
Map<Integer, String[]> history = new LinkedHashMap<>();
#Autowired
private SimpMessagingTemplate template;
private Integer count = 0;
#MessageMapping("/topic/history")
#SendTo("/topic/history")
public List<String[]> history(Integer to) {
return history.keySet()
.stream()
.filter(counter -> counter < to)
.map(counter -> history.get(counter))
.collect(Collectors.toList());
}
#Scheduled(fixedRate = 500)
public void sendMessage() {
DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
String[] str = {count.toString(), "name"+count,""+Math.round(Math.random()*100),"India"+Math.round(Math.random()*100),df.format(date)};
history.put(count, str);
this.template.convertAndSend("/topic/message",str);
++count;
}
}
In this sample, saved datas are stored in a map, be aware that it will consume some memory at some point.

reaching data with AngularJS2 and json

I need to develop an app for a conference and i'm trying to make this with Ionic2, AngularJS2 and Firebase.
I'm not starting from scratch, I clone this repository : https://github.com/driftyco/ionic-conference-app.
My repository : https://github.com/wowadrien/SFGP
My problem is that I need to filter the session first by day, next by room and then by theme so I add a level in the tree of my json to sort the session by room.
I've change the code of the data provider as this :
processData(data: any) {
this.data = data.json();
this.data.tracks = [];
// loop through each day in the schedule
this.data.schedule.forEach((day: any) => {
// loop through each timeline group in the day
day.groups.forEach((group: any) => {
// loop through each session in the timeline group
group.sessions.forEach((session: any) => {
//loop trough each subsession in the timeline session
session.subsessions.forEach((subsession: any) =>{
subsession.speakers = [];
if (subsession.speakerNames) {
subsession.speakerNames.forEach((speakerName: any) => {
let speaker = this.data.speakers.find((s: any) => s.name === speakerName);
if (speaker) {
subsession.speakers.push(speaker);
speaker.subsessions = speaker.subsessions || [];
speaker.subsessions.push(subsession);
}
});
}
if (subsession.tracks) {
subsession.tracks.forEach((track: any) => {
if (this.data.tracks.indexOf(track) < 0) {
this.data.tracks.push(track);
}
});
}
});
});
});
});
return this.data;
}
It doesn't work and i've tried about 20 differents solutions since last week but none of them was good.
I'm hopeless and lonely in this project so please, I need help !
Adrien

Transform Request to Autoquery friendly

We are working with a 3rd party grid (telerik kendo) that has paging/sorting/filtering built in. It will send the requests in a certain way when making the GET call and I'm trying to determine if there is a way to translate these requests to AutoQuery friendly requests.
Query string params
Sort Pattern:
sort[{0}][field] and sort[{0}][dir]
Filtering:
filter[filters][{0}][field]
filter[filters][{0}][operator]
filter[filters][{0}][value]
So this which is populated in the querystring:
filter[filters][0][field]
filter[filters][0][operator]
filter[filters][0][value]
would need to be translated to.
FieldName=1 // filter[filters][0][field]+filter[filters][0][operator]+filter[filters][0][value] in a nutshell (not exactly true)
Should I manipulate the querystring object in a plugin by removing the filters (or just adding the ones I need) ? Is there a better option here?
I'm not sure there is a clean way to do this on the kendo side either.
I will explain the two routes I'm going down, I hope to see a better answer.
First, I tried to modify the querystring in a request filter, but could not. I ended up having to run the autoqueries manually by getting the params and modifying them before calling AutoQuery.Execute. Something like this:
var requestparams = Request.ToAutoQueryParams();
var q = AutoQueryDb.CreateQuery(requestobject, requestparams);
AutoQueryDb.Execute(requestobject, q);
I wish there was a more global way to do this. The extension method just loops over all the querystring params and adds the ones that I need.
After doing the above work, I wasn't very happy with the result so I investigated doing it differently and ended up with the following:
Register the Kendo grid filter operations to their equivalent Service Stack auto query ones:
var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer=true };
aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");
Next, on the grid's read operation, we need to reformat the the querystring:
read: {
url: "/api/stuff?format=json&isGrid=true",
data: function (options) {
if (options.sort && options.sort.length > 0) {
options.OrderBy = (options.sort[0].dir == "desc" ? "-" : "") + options.sort[0].field;
}
if (options.filter && options.filter.filters.length > 0) {
for (var i = 0; i < options.filter.filters.length; i++) {
var f = options.filter.filters[i];
console.log(f);
options[f.field + f.operator] = f.value;
}
}
}
Now, the grid will send the operations in a Autoquery friendly manner.
I created an AutoQueryDataSource ts class that you may or may not find useful.
It's usage is along the lines of:
this.gridDataSource = AutoQueryKendoDataSource.getDefaultInstance<dtos.QueryDbSubclass, dtos.ListDefinition>('/api/autoQueryRoute', { orderByDesc: 'createdOn' });
export default class AutoQueryKendoDataSource<queryT extends dtos.QueryDb_1<T>, T> extends kendo.data.DataSource {
private constructor(options: kendo.data.DataSourceOptions = {}, public route?: string, public request?: queryT) {
super(options)
}
defer: ng.IDeferred<any>;
static exportToExcel(columns: kendo.ui.GridColumn[], dataSource: kendo.data.DataSource, filename: string) {
let rows = [{ cells: columns.map(d => { return { value: d.field }; }) }];
dataSource.fetch(function () {
var data = this.data();
for (var i = 0; i < data.length; i++) {
//push single row for every record
rows.push({
cells: _.map(columns, d => { return { value: data[i][d.field] } })
})
}
var workbook = new kendo.ooxml.Workbook({
sheets: [
{
columns: _.map(columns, d => { return { autoWidth: true } }),
// Title of the sheet
title: filename,
// Rows of the sheet
rows: rows
}
]
});
//save the file as Excel file with extension xlsx
kendo.saveAs({ dataURI: workbook.toDataURL(), fileName: filename });
})
}
static getDefaultInstance<queryT extends dtos.QueryDb_1<T>, T>(route: string, request: queryT, $q?: ng.IQService, model?: any) {
let sortInfo: {
orderBy?: string,
orderByDesc?: string,
skip?: number
} = {
};
let opts = {
transport: {
read: {
url: route,
dataType: 'json',
data: request
},
parameterMap: (data, type) => {
if (type == 'read') {
if (data.sort) {
data.sort.forEach((s: any) => {
if (s.field.indexOf('.') > -1) {
var arr = _.split(s.field, '.')
s.field = arr[arr.length - 1];
}
})
}//for autoquery to work, need only field names not entity names.
sortInfo = {
orderByDesc: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'desc'), 'field'), ','),
orderBy: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'asc'), 'field'), ','),
skip: 0
}
if (data.page)
sortInfo.skip = (data.page - 1) * data.pageSize,
_.extend(data, request);
//override sorting if done via grid
if (sortInfo.orderByDesc) {
(<any>data).orderByDesc = sortInfo.orderByDesc;
(<any>data).orderBy = null;
}
if (sortInfo.orderBy) {
(<any>data).orderBy = sortInfo.orderBy;
(<any>data).orderByDesc = null;
}
(<any>data).skip = sortInfo.skip;
return data;
}
return data;
},
},
requestStart: (e: kendo.data.DataSourceRequestStartEvent) => {
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if ($q)
ds.defer = $q.defer();
},
requestEnd: (e: kendo.data.DataSourceRequestEndEvent) => {
new DatesToStringsService().convert(e.response);
let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;
if (ds.defer)
ds.defer.resolve();
},
schema: {
data: (response: dtos.QueryResponse<T>) => {
return response.results;
},
type: 'json',
total: 'total',
model: model
},
pageSize: request.take || 40,
page: 1,
serverPaging: true,
serverSorting: true
}
let ds = new AutoQueryKendoDataSource<queryT, T>(opts, route, request);
return ds;
}
}