Unable to populate json to FormArray. TypeError: data.map is not a function - json

I am receiving this json format from api and need to populate it into FormArray. But am getting TypeError: data.map is not a function. Below is the code snippet.
{
"data": [
{
"id": "ASR4324368",
"name": "TTTTT",
"amount": 100
},
{
"id": "GTH435435435",
"name": "AAAAA",
"amount": 500
}
]
}
getProductJson() {
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.subscribe(
(data: any[]) => {
this.productForm = this.fb.group({
product: this.fb.array(
data.map(datum => this.generateDatumFormGroup(datum))
)
});
},
error => {
console.log(error);
}
);
}
private generateDatumFormGroup(datum) {
return this.fb.group({
id: this.fb.control({ value: datum.id, disabled: false }),
productName: this.fb.control({ value: datum.name, disabled: false }),
productAmt: this.fb.control({ value: datum.amount, disabled: false }),
});
}

are you sure you get data? to check use pipe(tap)
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.pipe(tap(res=>{console.log(res)})) //<--add this line
.subscribe(....rest-of your code...)
NOTE: I feel strange your request (but really I don't know if is ok) I ususally use some like
this.httpClient.get('http://myapi/api/controller/action', { withCredentials: true })

Modified to the below and was working.
getProductJson() {
this.httpClient.request('GET', 'getProductJSON', { withCredentials: true })
.subscribe(
(data: any[]) => {
this.raw = data;
this.productObj = this.raw.data;
this.productForm = this.fb.group({
product: this.fb.array(
this.productObj.map(datum => this.generateDatumFormGroup(datum))
)
});
},
error => {
console.log(error);
}
);
}

Related

Jest coverage in redux reducer - object destruction not covered

I have the following issue with Jest:
I have this reducer:
[REMOVE_FILTER]: (state: FiltersState, action: Action<string>): FiltersState => {
const { [action.payload!]: deleted, ...activeFilters } = state.activeFilters;
return { ...state, activeFilters, createFilterSelection: undefined, filterCreateOpen: false };
}
When I am trying to test it, it says that I do not have coverage for
...activeFilters } = state.activeFilters;
Here is my test:
test(REMOVE_FILTER, () => {
const action: IAction<string> = {
type: REMOVE_FILTER,
payload: "subprovider"
};
expect(
testReducer({ reducer, state, action })
).toEqual({
...state,
activeFilters: { name: null, branded: null },
createFilterSelection: undefined,
filterCreateOpen: false
});
});
Can someone suggest what I am doing wrong?
I am using:
Jest 23.6.0
Typescript 3.4.0
Redux 4.0.0
React-Redux: 6.0.0
Redux Actions: 2.6.1
Thank you!
P.S: Here is the Jest config:
{
"coverageThreshold": {
"global": {
"branches": 100,
"functions": 100,
"lines": 100,
"statements": 100
}
},
"globals": {
"window": true,
"document": true
},
"transform": {
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__test__/.*)\\.test\\.(ts|tsx)$",
"notify": true,
"collectCoverageFrom": [
"**/*.{ts,tsx}"
],
"coveragePathIgnorePatterns": [
"(/__e2e__/.*)",
"(/__specs__/.*)",
"(/__test__/.*)",
"(/interfaces/.*)",
"(index.ts)",
"(src/server/app.ts)",
"(src/server/config.ts)",
"(/mock/.*)",
"(data/mock.ts)",
"(automapperConfiguration.ts)",
"(src/app/store/store.ts)",
"(src/app/containers/brand-configuration/.*)"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"json"
],
"setupTestFrameworkScriptFile": "<rootDir>/jestSetup.js",
"testURL": "http://localhost/"
}
The above TS code gets transpilled to:
[REMOVE_FILTER]: (state, action) => {
const _a = state.activeFilters, _b = action.payload, deleted = _a[_b], activeFilters = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
return Object.assign({}, state, { activeFilters, createFilterSelection: undefined, filterCreateOpen: false });
}

Iterate a JSON array by a key value in react-native

Is there anyway to get a value in an object from a json array. I need to get a value from an object based on another value.
I have my code like:
export default class StandardComp extends Component {
constructor(props) {
super(props)
this.state = {
id: '',
email: 'abc#gmail.com',
dataSource: []
};
}
componentDidMount(){
fetch(someURL, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({dataSource: responseJson})
//dunno what to do here
})
.catch((error) => {
console.error(error);
})
}
}
My "responseJson" is something like this. Then providing the key value (abc#gmail.com), how could I get the string "abcdef"?
[
{
"id": "qwerty",
"email": "cat#gmail.com",
"name": "cat"
},
{
"id": "abcdef",
"email": "abc#gmail.com",
"name": "abc"
}
{
"id": "owowao",
"email": "dog#gmail.com",
"name": "dog"
},
]
Thank you in advance.
Find the element that matches email and return the id.
array::find
const data = [
{
"id": "qwerty",
"email": "cat#gmail.com",
"name": "cat"
},
{
"id": "abcdef",
"email": "abc#gmail.com",
"name": "abc"
},
{
"id": "owowao",
"email": "dog#gmail.com",
"name": "dog"
},
];
const findIdByEmail = (data, email) => {
const el = data.find(el => el.email === email); // Possibly returns `undefined`
return el && el.id; // so check result is truthy and extract `id`
}
console.log(findIdByEmail(data, 'cat#gmail.com'));
console.log(findIdByEmail(data, 'abc#gmail.com'));
console.log(findIdByEmail(data, 'gibberish'));
The code will depend on how you get the value abc#gmail.com.
You'll probably need to pass it in as an argument to componentDidMount via a prop? Or extract it to a separate function. It just depends.
Something like this is the most basic way I'd say.
const value = responseJson.filter(obj => obj.email === 'abc#gmail.com')[0].id
Here it is implemented in your class.
export default class StandardComp extends Component {
...
componentDidMount(){
fetch(someURL, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ dataSource: responseJson })
const { email } = this.state
const value = responseJson.filter(obj => obj.email === email)[0].id
})
.catch((error) => {
console.error(error);
})
}
}

GraphQL error update mutation "Resolve function for \"User.id\" returned undefined"

I am a newbie to GraphQL and trying to write an update mutation. However, I am receiving Resolve function for \"User.id\" returned undefined" error although the database is actually got updated.
What am I doing wrong?
userSchema.js:
import Sequelize from 'sequelize';
import SqlHelper from '../helpers/sqlhelper';
const config = require('../../config');
const sequelizer = new SqlHelper(config).Init();
const createUser = sequelizer.define(
'createUser',
{
...
}
);
const updateUser = sequelizer.define(
'updateUser',
{
id: {
type: Sequelize.UUID,
field: 'Id',
primaryKey: true,
defaultValue: Sequelize.UUIDV4,
},
username: {
type: Sequelize.STRING,
field: 'Username',
allowNull: true,
},
email: {
type: Sequelize.STRING,
field: 'Email',
allowNull: true,
},
firstname: {
type: Sequelize.STRING,
field: 'FirstName',
allowNull: true,
},
lastname: {
type: Sequelize.STRING,
field: 'LastName',
allowNull: true,
},
....
},
{
// define the table's name
tableName: 'Users',
},
);
module.exports = User;
UserResolver.js:
import User from '../dbschemas/user';
import Sequelize from 'sequelize';
const Op = Sequelize.Op;
export default {
Mutation: {
createUser: async (obj, args) =>
(await User.create(args)),
updateUser: async (obj, args) =>
(await User.update(args,
{
where: {
id: args.id,
},
returning: true
}))
}
};
Although calling updateUser from GraphiQL updates the records (in db), it results in a "Resolve function for \"User.id\" returned undefined" error:
mutation{
updateUser(id: "2ecd38ca-cf12-4e79-ac93-e922f24af9e3",
username: "newUserTesting",
email: "testemail#yahoo.com",
lastname: "TestUserLName",
firstname: "fname1") {
id
}
}
{
"data": null,
"errors": [
{
"message": "Resolve function for \"User.id\" returned undefined",
"locations": [
{
"line": 16,
"column": 4
}
],
"path": [
"updateUser",
"id"
]
}
]
}
The issue is clear, your resolver does not return an object containing id.
The docs say that Model.update returns an array in which the 2nd element is the affected row.
Hence, your resolver should look like:
async updateUser(obj, args) {
const resultArray = await User.update( ... )
return resultArray[1]
}
... To be replaced by whatever you need.
So apparently, update does NOT return affected rows for MSSQL, only the number of records affected.
This is true only for postgres when returning: true:
public static update(values: Object, options: Object): Promise<Array<affectedCount, affectedRows>>
Setting returning: true (for MSSQL) returns undefined (and order of params in the array is not even in the right order... i.e. first affectedRows -> undefined, then affectedCount ->num of affected rows.)
Tho get an object back you would need to do something like this:
Mutation: {
createUser: async (obj, args) =>
(await User.create(args.user)),
updateUser: async (obj, args, context, info) =>{
let user = args.user;
let response = await User.update(user,
{
where: {
[Op.or]: [{ email: user.email }, { id: user.id }, { username: user.username }, { lastname: user.lastname}]
},
//returning: true //not working... only for postgres db :(
}).then(ret => {
console.log('ret', ret);
return ret[0];
}).catch(error => {
console.log('error', error)
});
if (response > 0) return user; //return record
//return response > 0; //return true
}
}

Load form data via REST into vue-form-generator

I am building a form, that needs to get data dynamically via a JSON request that needs to be made while loading the form. I don't see a way to load this data. Anybody out here who can help?
JSON calls are being done via vue-resource, and the forms are being generated via vue-form-generator.
export default Vue.extend({
template,
data() {
return {
model: {
id: 1,
password: 'J0hnD03!x4',
skills: ['Javascript', 'VueJS'],
email: 'john.doe#gmail.com',
status: true
},
schema: {
fields: [
{
type: 'input',
inputType: 'text',
label: 'Website',
model: 'name',
maxlength: 50,
required: true,
placeholder: companyList
},
]
},
formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
},
companies: []
};
},
created(){
this.fetchCompanyData();
},
methods: {
fetchCompanyData(){
this.$http.get('http://echo.jsontest.com/key/value/load/dynamicly').then((response) => {
console.log(response.data.company);
let companyList = response.data.company; // Use this var above
}, (response) => {
console.log(response);
});
}
}
});
You can just assign this.schema.fields.placeholder to the value returned by the API like following:
methods: {
fetchCompanyData(){
this.$http.get('http://echo.jsontest.com/key/value/load/dynamicly').then((response) => {
console.log(response.data.company);
this.schema.fields.placeholder = response.data.company
}, (response) => {
console.log(response);
});
}
}

aurelia bridge kendo grid refresh

I'm trying to use Aurelia KendoUi Bridge in my application.
In my code I have a service which returns a new KendoDataSource :
export class KendoDataSource {
ToKendoDataSource(data: any, recordCount: number, pageSize: number, currentPage: number): any {
return {
transport: {
read: (p) => {
p.success({ data: data, recordCount: recordCount });
}
},
pageSize: pageSize,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
data: (result) => {
console.log('Transforming data to kendo datasource.');
return result.data;
},
total: (result) => {
return result.recordCount;
}
}
};
}
}
And this is my viewModel:
#inject(HttpService, KendoDataSource, EventAggregator)
export class GroupList {
grid: any;
gridVM: any;
datasource: any;
pageable: any;
subscriber: any;
paginationDetailsRequest: PaginationDetailsRequest;
test: string;
constructor(private httpService: HttpService, private kendoDataSource: KendoDataSource, private eventAggregator: EventAggregator) {
this.httpService = httpService;
this.kendoDataSource = kendoDataSource;
this.eventAggregator = eventAggregator;
this.paginationDetailsRequest = new PaginationDetailsRequest(4, 1);
this.GetGroups(this.paginationDetailsRequest);
this.datasource = {
transport: {
read: {
url: 'PersonGroup/GetGroups',
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json'
},
parameterMap: function (data, type) {
if (type == "read") {
let paginationDetails = new PaginationDetailsRequest(data.pageSize, data.page);
if(data.sort && data.sort.length > 0){
paginationDetails.orderBy = data.sort[0].field;
paginationDetails.OrderDesc = (data.sort[0].dir == 'desc');
}
console.log(this.datasource);
return JSON.stringify(paginationDetails);
}
}
},
schema: {
data: "data.currentPageData",
total: "data.totalCount"
},
pageSize: 2,
serverPaging: true,
serverFiltering: true,
serverSorting: true
};
};
attached() {
this.subscriber = this.eventAggregator.subscribe('Search', response => {
this.search(response);
});
}
activate() {
this.pageable = {
refresh: true,
pageSizes: true,
buttonCount: 10
};
}
GetGroups(paginationDetails: PaginationDetailsRequest): void {
this.httpService.post('PersonGroup/GetGroups', paginationDetails)
.then(response => response.json())
.then(groups => {
console.log(groups);
if (groups.succeeded) {
this.datasource = this.kendoDataSource.ToKendoDataSource(groups.data.currentPageData, groups.totalCount, groups.pageSize, groups.currentPage);
this.grid.setDataSource(this.datasource); // initialize the grid
}
else {
//TODO: Show error messages on screen
console.log(groups.errors);
}
})
.catch(error => {
//TODO: Show error message on screen.
console.log(error);
});
}
search(searchDetails: Filter) {
console.log(searchDetails);
this.paginationDetailsRequest.filters.push(searchDetails);
console.log(this.paginationDetailsRequest);
this.GetGroups(this.paginationDetailsRequest);
}
detached() {
this.subscriber.dispose();
}
}
I understand that kendo does not have two-way data binding, But I'm trying to find a way to refresh the grid when I filter the data and the data source has changed.
Thanks.
I had this problem and found the solution by creating a new dataSource and assigning it to setDataSource, as follows... Note, getClients() is a search activated by a button click.
Here is the grid:
<ak-grid k-data-source.bind="datasource"
k-pageable.bind="{ input: true, numeric: false}"
k-filterable.bind="true"
k-sortable.bind="true"
k-scrollable.bind="true"
k-widget.bind="clientgrid"
k-selectable.bind="true">
<ak-col k-title="First Name" k-field="firstName" k-width="120px"></ak-col>
<ak-col k-title="Last Name" k-field="lastName" k-width="120px"></ak-col>
<ak-col k-title="Email Address" k-field="primaryEmail" k-width="230px"></ak-col>
</ak-grid>
And here is the code that updates the dataSource
public getClients()
{
console.log("ClientService.getClients");
this.clientService.getClients()
.then(result =>
{
this.clientList = result;
// the new datasource in the next line is displayed
// after the call to setDataSource(ds) below.
let ds: kendo.data.DataSource = new kendo.data.DataSource({
data: this.clientList,
schema: {
model: {
id: "id",
fields: {
firstName: { type: 'string' },
id: { type: 'number' },
lastName: { type: 'string' },
primaryEmail: { type: 'string' }
}
}
},
pageSize: 10
});
this.clientgrid.setDataSource(ds);
this.clientgrid.refresh();
})
.catch(err => console.log("Error returned from getClients " + err));
}
You don't really need to create a brand new datasource. To refresh the grid after changing the underlying data you can just replace the data element in the dataSource like so:
this.clientgrid.dataSource.data(this.datasource.data);