Angular2 RC5: get json data from web service not working - json

I am trying to load data from data service but ID appears as type error
selectedModule(item: any) {
this.module = item;
console.log(this.module);
this.dataService.getAny('/modules/get-by-module', "Id", '1')
.then((module: IModuleBySector) => {
const cust = JSON.stringify(module);
this.moduleSelected = module;
console.log(this.moduleSelected);
});
}

I believe you want to send ID to the server side code and want to get data whose ID=1. You should try this,
selectedModule(item: any) {
this.module = item;
console.log(this.module);
this.dataService.getAny('/modules/get-by-module?Id=1')
.then((module: IModuleBySector) => {
const cust = JSON.stringify(module);
this.moduleSelected = module;
console.log(this.moduleSelected);
});
}

Related

Apply search columns and export mat table to excel

I am trying to implement a reports feature in my application which pulls country wise reports for a person logged in. I am getting data from backend and displaying this in a mat table. I want to have different filters based on country, sectors, industries on this data and it should also have the feature to export it.. For the filtering i dont want to run a backend query everytime so i want to filter it in the frontend and export the given data. I tried the table_to_sheet option of xlsx but that only exports the first page of the table. My code:
Object:
export interface Reports {
projectId: string;
projectName: string;
industry: string;
sector: string;
}
my table looks like this
I want to update the data array every time I apply a filter and then export the same. Can anyone help.
I am assigning the table in ngonInit
ngOnInit(): void {
this.service.getReports(this.loggedUser, this.role).subscribe
(
(res: any) => {
this.showSpinner = false
this.showTable = true
console.log(res)
console.log(res.reportList)
console.log('filters: ' +res.reportFilter.countrySet)
this.dataSourceMyRequests = new MatTableDataSource(res.reportList) ;
this.countryList = res.reportFilter.countrySet
this.gcnList = res.reportFilter.countrySet
this.sectorList = res.reportFilter.countrySet
//this.dataSourceMyRequests.sort = this.sortRequest
//this.dataSourceMyRequests.paginator = this.paginatorRequest
this.showData = true;
},
(error) => {
this.showSpinner = false
this._snackbar.open('No data found!', 'OK');
console.log(error)
}
)
}
I want to write a filter method like below:
filter(searchField, searchValue){
}
For filtering build a frontend filter that gets applied to incoming array of items. After filtering show only filtered items in table.
If filter returns true, then filteredArray will include it.
filteredArray: any[];
observable.subscribe((allData) => {
this.filteredArrray = allData.filter((item) => {
if (item?.projectId === '123') {
return true;
} else if (item?.projectName === 'name') {
return true;
} else {
return false;
}
});
})
Then export filteredArray[] to xlsx: https://stackblitz.com/edit/angular-material-table-export-excel-xlsx?file=app%2FtableUtil.ts

Too tidious hooks when querying in REST. Any ideas?

I've just started using feathers to build REST server. I need your help for querying tips. Document says
When used via REST URLs all query values are strings. Depending on the service the values in params.query might have to be converted to the right type in a before hook. (https://docs.feathersjs.com/api/databases/querying.html)
, which puzzles me. find({query: {value: 1} }) does mean value === "1" not value === 1 ? Here is example client side code which puzzles me:
const feathers = require('#feathersjs/feathers')
const fetch = require('node-fetch')
const restCli = require('#feathersjs/rest-client')
const rest = restCli('http://localhost:8888')
const app = feathers().configure(rest.fetch(fetch))
async function main () {
const Items = app.service('myitems')
await Items.create( {name:'one', value:1} )
//works fine. returns [ { name: 'one', value: 1, id: 0 } ]
console.log(await Items.find({query:{ name:"one" }}))
//wow! no data returned. []
console.log(await Items.find({query:{ value:1 }})) // []
}
main()
Server side code is here:
const express = require('#feathersjs/express')
const feathers = require('#feathersjs/feathers')
const memory = require('feathers-memory')
const app = express(feathers())
.configure(express.rest())
.use(express.json())
.use(express.errorHandler())
.use('myitems', memory())
app.listen(8888)
.on('listening',()=>console.log('listen on 8888'))
I've made hooks, which works all fine but it is too tidious and I think I missed something. Any ideas?
Hook code:
app.service('myitems').hooks({
before: { find: async (context) => {
const value = context.params.query.value
if (value) context.params.query.value = parseInt(value)
return context
}
}
})
This behaviour depends on the database and ORM you are using. Some that have a schema (like feathers-mongoose, feathers-sequelize and feathers-knex), will convert values like that automatically.
Feathers itself does not know about your data format and most adapters (like the feathers-memory you are using here) do a strict comparison so they will have to be converted. The usual way to deal with this is to create some reusable hooks (instead of one for each field) like this:
const queryToNumber = (...fields) => {
return context => {
const { params: { query = {} } } = context;
fields.forEach(field => {
const value = query[field];
if(value) {
query[field] = parseInt(value, 10)
}
});
}
}
app.service('myitems').hooks({
before: {
find: [
queryToNumber('age', 'value')
]
}
});
Or using something like JSON schema e.g. through the validateSchema common hook.

Angular 2 - Getting object id from array and displaying data

I currently have a service that gets an array of json objects from a json file which displays a list of leads. Each lead has an id and when a lead within this list is clicked it takes the user to a view that has this id in the url ie ( /lead/156af71250a941ccbdd65f73e5af2e67 )
I've been trying to get this object by id through my leads service but just cant get it working. Where am I going wrong?
Also, i'm using two way binding in my html.
SERVICE
leads;
constructor(private http: HttpClient) { }
getAllLeads() {
return this.http.get('../../assets/leads.json').map((response) => response);
}
getLead(id: any) {
const leads = this.getAllLeads();
const lead = this.leads.find(order => order.id === id);
return lead;
}
COMPONENT
lead = {};
constructor(
private leadService: LeadService,
private route: ActivatedRoute) {
const id = this.route.snapshot.paramMap.get('id');
if (id) { this.leadService.getLead(id).take(1).subscribe(lead => this.lead = lead); }
}
JSON
[
{
"LeadId": "156af71250a941ccbdd65f73e5af2e66",
"LeadTime": "2016-03-04T10:53:05+00:00",
"SourceUserName": "Fred Dibnah",
"LeadNumber": "1603041053",
},
{
"LeadId": "156af71250a999ccbdd65f73e5af2e67",
"LeadTime": "2016-03-04T10:53:05+00:00",
"SourceUserName": "Harry Dibnah",
"LeadNumber": "1603021053",
},
{
"LeadId": "156af71250a999ccbdd65f73e5af2e68",
"LeadTime": "2016-03-04T10:53:05+00:00",
"SourceUserName": "John Doe",
"LeadNumber": "1603021053",
}
]
You didn't used the newly created leads array (const leads is not this.leads), so do this:
getLead(id: any) {
return this.getAllLeads().find(order => order.LeadId === id);
}
And change your map to flatMap, because from the server you get an array, but you have to transform it to a stream of its items:
getAllLeads() {
return this.http.get('../../assets/leads.json').flatMap(data => data);
}
Don't forget to import it if you have to: import 'rxjs/add/operator/flatMap';
You can have getLead in your component level itself since you are not making any api to get the information. In your component,
this.lead = this.leads.find(order => order.id === id);
or to make the above service work, just do leads instead of this.leads
const lead = leads.find(order => order.id === id);

Redux, Fetch and where to use .map

Consider this scenario:
app loads => fetches json from api => needs to modify json returned
In this case, I'm using moment to make some date modifications and do some grouping that I'll use in the UI. I looked on stack and found a similar question but didn't feel like it provided the clarity I am seeking.
Where should I use .map to create the new objects that contain the formatted & grouped dates? Should I manipulate the raw json in the api call or in the redux action before I dispatch? What is the best practice?
Is it OK to add properties and mutate the object as I am showing below,
service["mStartDate"] = mStartDate before I put the data into my store and treat it as immutable state?
First Approach - changing raw json in the api call
class TicketRepository extends BaseRepository {
getDataByID(postData) {
return this.post('api/lookup', postData)
.then(result => {
const groupedData = {}
return result.map(ticket => {
const mStartDate = moment(ticket.startDate)
const mEndDate = moment(ticket.endDate)
const serviceLength = mStartDate.diff(mEndDate,'hours')
const duration = moment.duration(serviceLength,"hours").humanize()
const weekOfYear = mStartDate.format('WW')
const dayOfWeek = mStartDate.format("d")
if(!groupedData.hasOwnProperty(weekOfYear)){
groupedData[weekOfYear] = {}
}
if (!groupedData[weekOfYear].hasOwnProperty(dayOfWeek)) {
groupedData[weekOfYear][dayOfWeek] = []
}
service["mStartDate"] = mStartDate
service["mEndDate"] = mEndDate
service["serviceLength"] = serviceLength
service["duration"] = duration
groupedData[weekOfYear][dayOfWeek].push(service)
})
})
}
}
2nd Approach, make a simple api call
class TicketRepository extends BaseRepository {
getDataByID(postData) {
return this.post('api/lookup', postData)
}
}
Change the json in the action before dispatching
export function getDataByID() {
return (dispatch, getState) => {
dispatch(dataLookupRequest())
const state = getState()
const groupedData = {}
return TicketRepository.getDataByID(userData)
.then(result => {
const groupedData = {}
return result.map(ticket => {
const mStartDate = moment(ticket.startDate)
const mEndDate = moment(ticket.endDate)
const serviceLength = mStartDate.diff(mEndDate,'hours')
const duration = moment.duration(serviceLength,"hours").humanize()
const weekOfYear = mStartDate.format('WW')
const dayOfWeek = mStartDate.format("d")
if(!groupedData.hasOwnProperty(weekOfYear)){
groupedData[weekOfYear] = {}
}
if (!groupedData[weekOfYear].hasOwnProperty(dayOfWeek)) {
groupedData[weekOfYear][dayOfWeek] = []
}
service["mStartDate"] = mStartDate
service["mEndDate"] = mEndDate
service["serviceLength"] = serviceLength
service["duration"] = duration
groupedData[weekOfYear][dayOfWeek].push(service)
})
return groupedData
})
.then(groupedData => {
dispatch(lookupSuccess(groupedData))
})
.catch(err => dispatch(dataLookupFailure(err.code, err.message)))
}
}
All data manipulation should be handled by your reducer. That is, the returned response data should be passed on to a reducer. This practice is common, because this way if there's a problem with your data, you will always know where to look - reducer. So neither of your approaches is "correct". Actions should just take some input and dispatch an object (no data manipulation).
When you want to manipulate data for 'view' purposes only, consider using reselect library, which makes it easier to handle "data views" that are composed of the existing data.

Working with JSON data.. why are all properties of my object undefined?

I am attempting to take the Name and ID fields from each object, but the fields are appearing undefined.
function OnHistoricalListBoxLoad(historicalListBox) {
$.getJSON('GetHistoricalReports', function (data) {
historicalListBox.trackChanges();
$.each(data, function () {
var listBoxItem = new Telerik.Web.UI.RadListBoxItem();
listBoxItem.set_text(this.Name);
listBoxItem.set_value(this.ID);
historicalListBox.get_items().add(listBoxItem);
});
historicalListBox.commitChanges();
});
}
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetHistoricalReports()
{
List<HistoricalReport> historicalReports = DashboardSessionRepository.Instance.HistoricalReports;
var viewModel = historicalReports.Select(report => new
{
ID = report.ID,
Name = report.Name
}).ToArray();
return Json(viewModel, JsonRequestBehavior.AllowGet);
}
I know that I am returning the data successfully, and I know that there is valid data. I am new to MVC/JavaScript, though.. I checked case sensitivity to ensure that I wasn't making just an easy mistake, but it does not seem to be the issue. Am I missing something more complex?
Inspecting the HTTP Response JSON tab in Chrome I see:
0: {ID:1, Name:PUE}
1: {ID:2, Name:Weight}
2: {ID:3, Name:Power Actual vs Max}
3: {ID:4, Name:Power Actual}
No idea, but passing such behemoth domain models to views is very bad practice. This is so kinda domain polluted that it has nothing to do in a view. In a view you work with views models. View models contain only what a view needs. In this case your view needs an ID and a Name. So pass a view model with only those single simple properties to this view:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetHistoricalReports()
{
var reports = DashboardSessionRepository.Instance.HistoricalReports;
var reportsViewModel = reports.Select(x => new
{
ID = x.ID,
Name = x.Name
}).ToArray();
return Json(reportsViewModel, JsonRequestBehavior.AllowGet);
}
Now, not only that you will save bandwidth, but you will get some clean JSON:
[ { ID: 1, Name: 'Foo' }, { ID: 2, Name: 'Bar' }, ... ]
through which you will be able to loop using $.each.
UPDATE:
Now that you have shown your JSON data it seems that there is a Content property which represents the collection. So you need to loop through it:
$.each(data.Content, ...);
and if you follow my advice about the view models your controller action would become like this:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetHistoricalReports()
{
var report = DashboardSessionRepository.Instance.HistoricalReports;
var reportsViewModel = report.Content.Select(x => new
{
ID = x.ID,
Name = x.Name
}).ToArray();
return Json(reportsViewModel, JsonRequestBehavior.AllowGet);
}
and now loop directly through the returned collection:
$.each(data, ...);