Ember adds empty row to data with slug as id - ajax

I have a resource where I list all my projects from server /projects. You can visit specific project going to /projects/:slug.
When I visit projects resource I see this data in Ember Inspector:
/projects
id | Slug | Title |
-------------------------------------------------
1 | first-project | First project |
-------------------------------------------------
2 | second-project | Second project |
-------------------------------------------------
3 | third-project | Third project |
When I visit a project from list of projects I get the same data without new ajax request and everything is working fine. /projects/first-project
The problem comes when I refresh /projects/first-project page. Ember makes an ajax request to fetch data from server but It also inserts an empty row with slug as id to data.
id | Slug | Title |
-------------------------------------------------------------
first-project | | |
-------------------------------------------------------------
1 | first-project | First project |
Now visiting project list It is showing a list of projects but at the top of the list is this empty row. Why it is inserting this slug row to my data? Maybe my logic is wrong.
<li>
<a id="ember451" class="ember-view" href="/projects/undefined">
<script id="metamorph-13-start" type="text/x-placeholder"></script>
<script id="metamorph-13-end" type="text/x-placeholder"></script>
</a>
</li>
My code for projects:
App.Router.map(function() {
this.resource('project', { path: '/projects' }, function() {
this.resource('project.show', { path: ":post_slug"});
});
});
App.Project = DS.Model.extend({
slug: DS.attr("string"),
title: DS.attr("string")
});
App.ProjectIndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('project').then(function(data) {
return data;
});
}
});
App.ProjectShowRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('project', params.post_slug).then(function(data) {
return data;
});
},
serialize: function(model) {
return { post_slug: model.get("slug") };
}
});
I'm using:
DEBUG: -------------------------------
DEBUG: Ember : 1.1.2
DEBUG: Ember Data : 1.0.0-beta.3
DEBUG: Handlebars : 1.0.0
DEBUG: jQuery : 1.9.1
DEBUG: -------------------------------

Adding this helps. now primary key is slug for Project model and it doesn't duplicate rows.
App.ProjectSerializer = DS.RESTSerializer.extend({
normalize: function(type, hash, property) {
hash.id = hash.slug;
return this._super(type, hash, property);
}
});

By calling
store.find('project', 'first-project')
you're treating the slug as the primary key. I guess that's the reason that a new record is initialized (you have one with the actual primary key of the first project which is probably a number, and one with 'first-project' as the primary key.
Try changing the model hook by calling the store's find() method with a hash of search options, in your case:
store.find('project', { slug: 'first-project' })

There are two other ways to solve this problem without extending the RESTSerializer.
First method: If you can make sure that the slug str is unique across the whole app, and you don't really care about id numbers. Then you can set the ids for each project using the slug str because ids don't have to be numbers.
{ id: 'first-project', content: 'xxx' }
{ id: 'second-project', content: 'yyy' }
Second method. use the modelFor method. example code below:
App.ProjectShowRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('its_parent_route').findBy('slug', params.post_slug);
},
serialize: function(model) {
return { post_slug: model.get("slug") };
}
});
By calling modelFor here, it won't make duplicate calls to the server since you're using ember data.
Hope it helps.

Related

Unable to Reference new Strapi Entry

I have the following code ...
const createThenReference = async () => {
return await axios.post('http://localhost:1337/firsts', {
name: "Jeremy"
})
.then(async (res)=>{
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data
})
.then((res)=>{console.log(res)})
.catch((err)=>{console.log(err)})
})
.catch((err)=>{console.log(err)})
}
The fields of each table is as follows ...
First = { name: String, second: Relationship }
Second = { name: String, first: Relationship }
What I am trying to achieve is that after the firsts entry is created, a new one in seconds is created and it references back to the firsts in a 1-to-1 reference.
I've had success referencing items that were already created in a similar way of just passing them into their appropriate field in the payload. However, when it is recently created I have issues. -- I'm unable to find any documentation that even talks about creating references from the front end.
Apparently you can simply pass in the ID of the table entry that has a relationship to that field. -- Which is odd because I remember trying that before and it didn't work.
I changed ...
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data
})
to
await axios.post('http://localhost:1337/seconds', {
name: "Jonathan",
first: res.data.id
})
And the relationship was properly set up.
For more information check out this Strapi post Understanding and using Relations in Strapi

How to modify just a property from a dexie store without deleting the rest?

I'm having the dexie stores showed in the print screen below:
Dexie stores print screen
My goal is to update a dexie field row from a store without losing the rest of the data.
For example: when I edit and save the field "com_name" from the second row (key={2}) I want to update "com_name" only and not lose the rest of the properties, see first and the third row.
I already tried with collection.modify and table.update but both deleted the rest of the properties when used the code below:
dexieDB.table('company').where('dexieKey').equals('{1}')
//USING table.update
//.update(dexieRecord.dexiekey, {
// company: {
// com_name: "TOP SERVE 2"
// }
//})
.modify(
{
company:
{
com_name: TOP SERVE 2
}
}
)
.then(function (updated) {
if (updated)
console.log("Success.");
else
console.log("Nothing was updated.");
})
.catch(function (err) { console.log(err); });
Any idea how can I accomplish that?
Thanks
Alex
You where right to use Table.update or Collection.modify. They should never delete other properties than the ones specified. Can you paste a jsitor.com or jsfiddle repro of that and someone may help you pinpoint why the code doesn't work as expected.
Now that you are saying I realised that company and contact stores are created dynamically and editedRecords store has the indexes explicitly declared therefore when update company or contact store, since dexie doesn't see the indexes will overwrite. I haven't tested it yet but I suspect this is the behaviour.
See the print screen below:
Dexie stores overview
Basically I have json raw data from db and in the browser I create the stores and stores data based on it, see code below:
function createDexieTables(jsonData) { //jsonData - array, is the json from db
const stores = {};
const editedRecordsTable = 'editedRecords';
jsonData.forEach((jsonPackage) => {
for (table in jsonPackage) {
if (_.find(dexieDB.tables, { 'name': table }) == undefined) {
stores[table] = 'dexieKey';
}
}
});
stores[editedRecordsTable] = 'dexieKey, table';
addDataToDexie(stores, jsonData);
}
function addDataToDexie(stores, jsonData) {
dbv1 = dexieDB.version(1);
if (jsonData.length > 0) {
dbv1.stores(stores);
jsonData.forEach((jsonPackage) => {
for (table in jsonPackage) {
jsonPackage[table].forEach((tableRow) => {
dexieDB.table(table).add(tableRow)
.then(function () {
console.log(tableRow, ' added to dexie db.');
})
.catch(function () {
console.log(tableRow, ' already exists.');
});
});
}
});
}
}
This is the json, which I convert to object and save to dexie in the value column and the key si "dexieKey":
[
{
"company": [
{
"dexieKey": "{1}",
"company": {
"com_pk": 1,
"com_name": "CloudFire",
"com_city": "Round Rock",
"serverLastEdit": [
{
"com_pk": "2021-06-02T11:30:24.774Z"
},
{
"com_name": "2021-06-02T11:30:24.774Z"
},
{
"com_city": "2021-06-02T11:30:24.774Z"
}
],
"userLastEdit": []
}
}
]
}
]
Any idea why indexes were not populated when generating them dynamically?
Given the JSON data, i understand what's going wrong.
Instead of passing the following to update():
{
company:
{
com_name: "TOP SERVE 2"
}
}
You probably meant to pass this:
{
"company.com_name": "TOP SERVE 2"
}
Another hint is to do the add within an rw transaction, or even better if you can use bulkAdd() instead to optimize the performance.

Prisma Not Returning Created Related Records

i want to create a new graphql api and i have an issue that i am struggling to fix.
the code is open source and can be found at: https://github.com/glitr-io/glitr-api
i want to create a mutation to create a record with relations... it seems the record is created correctly with all the expected relations, (when checking directly into the database), but the value returned by the create<YourTableName> method, is missing all the relations.
... so so i get an error on the api because "Cannot return null for non-nullable field Meme.author.". i am unable to figure out what could be wrong in my code.
the resolver looks like the following:
...
const newMeme = await ctx.prisma.createMeme({
author: {
connect: { id: userId },
},
memeItems: {
create: memeItems.map(({
type,
meta,
value,
style,
tags = []
}) => ({
type,
meta,
value,
style,
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
}))
},
tags: {
create: tags.map(({ name = '' }) => (
{
name
}
))
}
});
console.log('newMeme', newMeme);
...
that value of newMeme in the console.log here (which what is returned in this resolver) is:
newMeme {
id: 'ck351j0f9pqa90919f52fx67w',
createdAt: '2019-11-18T23:08:46.437Z',
updatedAt: '2019-11-18T23:08:46.437Z',
}
where those fields returned are the auto-generated fields. so i get an error for a following mutation because i tried to get the author:
mutation{
meme(
memeItems: [{
type: TEXT
meta: "test1-meta"
value: "test1-value"
style: "test1-style"
}, {
type: TEXT
meta: "test2-meta"
value: "test2-value"
style: "test2-style"
}]
) {
id,
author {
displayName
}
}
}
can anyone see what issue could be causing this?
(as previously mentioned... the record is created successfully with all relationships as expected when checking directly into the database).
As described in the prisma docs the promise of the Prisma client functions to write data, e.g for the createMeme function, only returns the scalar fields of the object:
When creating new records in the database, the create-method takes one input object which wraps all the scalar fields of the record to be
created. It also provides a way to create relational data for the
model, this can be supplied using nested object writes.
Each method call returns a Promise for an object that contains all the
scalar fields of the model that was just created.
See: https://www.prisma.io/docs/prisma-client/basic-data-access/writing-data-JAVASCRIPT-rsc6/#creating-records
To also return the relations of the object you need to read the object again using an info fragment or the fluent api, see: https://www.prisma.io/docs/prisma-client/basic-data-access/reading-data-JAVASCRIPT-rsc2/#relations

Can't find cache key in Cache redirect

When I start my react-native app I wan't to query "everything" for an offline experience.
So I
query all {
groups {
...GroupF
}
persons {
...PersonF
}
}${PERSON_ITEM}${GROUP_ITEM}
PersonF and GroupF are fragments.
The first view has a list of groups, each person can belong to a group. When the user clicks on an group the query looks like:
persons($group: ID) {
persons(group: $group) {
...PersonsF
}
}${PERSON_ITEM}
But my cacheRedirects just does not reflect the same data as is returned.
I know this because i console.log out the response in my component wrapper (it looks excellent here)
but in my
const cache = new InMemoryCache({
cacheRedirects: {
Query: {
persons: (_, args, {getCacheKeys}) => {
// I have tried everything here but nothing maps correctly
// I have tried getCacheKey({__typename: 'Person', id: args.group})
// I have tried following the apollo documentation
// No luck, it just can't find the group
// Using the chrome dev tools I don't see persons having groups
const a = getCacheKey({__typename: 'Person', id: args.group});
// Console.log(a) is:
// {generated: false, id: "Person:9", type: "id", typename "Person"}
}
}
}
});
Do you have any suggestions on how I can write a proper cache redirects persons query?
Help really really really appreciated
|1| https://www.apollographql.com/docs/react/advanced/caching.html#cacheRedirect
This was caused by the fact we used the id field in the Person, since we stoped using the field it works perfectly.

CGI::Ajax can not control returned table css style?

I have question regarding using CGI::Ajax.
my CGI::Ajax registered function will return a table, and I want to control the table's style by using jquery plugin tablesorter
the result table is returned, but I just can not control the style of it, i.e, I can not sort the table with using the plugin tablesorter in calling function
major part of code is as below, these are just part of the code, if there are some punctuation problems, please ignore it
as you can see, the main program, "show_html", can sort the table, "metatable"; however, the return table, "resulttable" can not be sorted even if I put id='resulttable' there.
Could someone help me with this issue?
Thank you
my $cgi = CGI->new();
my $pjx = CGI::Ajax->new('js_fun'=>\&perl_fun);
sub per_fun{
...
print $cgi->start_table({id=>'resulttable'}),
...
}
sub show_html{ //partial code
print $html_fh $cgi->start_html(
-title=>'Selected GEO MetaData',
-style=> {-src=>[ "jquery-ui-1.8.20.custom.css",
"jq_tablesorter/themes/green/style.css",
"jq_ui_redmond/css/selectable.css",
]
},
-script=>[
{ -type => "text/javascript",
-src => "$tempdir/jq/js/jquery-1.7.2.min.js"
},
{ -type => 'text/javascript',
-src => "$tempdir/jq/jq_tablesorter/jquery.tablesorter.min.js"
},
{ -type => 'text/javascript',
-src => "$tempdir/jq/jq_ui_redmond/js/jquery-ui-1.8.20.custom.min.js"
},
q<
$(document).ready(function(){
$("#metatable").tablesorter();
$("#resulttable").tablesorter();
)}
....
$("#done").click(function(){
$("#metatable").slideUp();
js_fun(['val1'],['result1']); //ajax
return false;
})
.....
print $cgi->div({id=>'result1'});
.....
}
The binding of the result table to the sort method has to be redone after the AJAX request returns successfully, something like this:
$.post("ajax/jsfun", "['val1']", function(data) {
$('#resulttable').html(data);
$("#resulttable").tablesorter();
});

Resources