I just ran into a problem where I am not sure how to solve.
Background: I've got an App with two views:
1st one to input a number,
2nd one to see the details.
After the view switched to the detail view, I would call the bindElement() to get my data from the backend.
_onRoutePatternMatched: function(oEvent) {
// ...
this.getView().bindElement({
path: "/EntitySet('" + id+ "')"
});
},
Problem is that the ID is quite often the same, hence, the method will call the backend only if the ID is different from the last call.
So I tried to solve the problem by using the following:
this.getView().getModel().read("/EntitySet('" + id+ "')",{
success: function(oData, response) {
that.getView().setModel(oData, "");
}
});
By this, the data is always up to date. But now the binding is a bit different.
Binding with bindElement():
{
"id": "1234",
"propety1": "abc",
// ...
}
Binding with setModel() and id = 1234:
{
"EntitySet('1234')": {
"id": "1234",
"propety1": "abc",
// ...
}
}
For the first way, my binding looked like this:
<ObjectHeader title="{id}">
Now, it would have to look like this:
<ObjectHeader title="{/EntitySet('1234')/id}">
And here I have a problem, because the value of id (in this case 1234) will always be different and so the binding won't work. I can't bind directly to the ObjectHeader, because I will need some properties from the model later. That is the reason I am binding to the view so that all that remain available.
My idea was to edit the binding inside the success method of the read method. I would like to delete the surrounding element. Do you have an idea, how to do this? Or even a simpler/better idea to solve my pity?
Edit:
I forgot to mention the refresh method. This would be possible, but where do I have to put it? I don't want to call the backend twice.
Simply call the API myODataModel.invalidateEntry(<key>) before binding the context in order to retrieve the latest data.
// after $metadata loaded..
const model = this.getOwnerComponent().getModel("odata");
const key = model.createKey(/*...*/) //See https://stackoverflow.com/a/47016070/5846045
model.invalidateEntry(key); // <-- before binding
this.getView().bindElement({
path: "odata>/" + key,
// ...
});
From https://embed.plnkr.co/b0bXJK?show=controller/Detail.controller.js,preview
invalidateEntrydoc
Invalidate a single entry in the model data.
Mark the selected entry in the model cache as invalid. Next time a context binding or list binding is done, the entry will be detected as invalid and will be refreshed from the server.
Related
I do load aittable records via their API:
const base = airtable.base(item.baseId);
base("Dishes")
.select({
})
.eachPage(
function page(records, fetchNextPage) {
tableRecords.push(...records);
// To fetch the next page of records, call `fetchNextPage`.
// If there are more records, `page` will get called again.
// If there are no more records, `done` will get called.
fetchNextPage();
},
function done(err) {
if (err) {
console.error(err);
return;
}
console.log("##Done", tableRecords.length);
}
);
and as a result, I receive 2202 records. But in the table in UI I do see 2271 records. And when I do export to csv - I see the same 2271 as well.
Code is pretty basic, I even remove view setting to ensure, that it's not a presentational issue.
Google did not help me (nothing related). Did anyone face the same issue? Any solution?
NB: for sure I already compared both lists and found items I do miss, but while observing those items I see nothing special there. So it says me what I do miss, but not why
const base = airtable.base(item.baseId);
base("Dishes")
.select({})
.all()
I want to use a table for navigation purposes. Therefore I use the following code (the table looks good, all datas are complete):
// Admin.view.xml View
<Table id="objectsTable" itemPress="onSelectionChange">
// Admin.controller.js Controller
onSelectionChange: function(event) {
// After call undefined
var partnerId = event.getSource().getBindingContext().getProperty("BUSINESS_PARTNER_ID");
// After call defined and correct
var objectId = event.getSource().getBindingContext().getProperty("ID");
var router = this.getOwnerComponent()
.getRouter();
router.navTo("adminDetails", {
partner: partnerId,
object: objectId
});
After debugging I found out, that the value objectIdis undefined (while ID is present). This causes the navigation to not work properly.
So I looked at the data source (oData), which looks as follows :
ID | BUSINESS_PARTNER_ID | ADDRESS | FILES (oData association/navigation) |
.... All records are available, including the BUSINESS_PARTNER_ID
Why is the variable BUSINESS_PARTNER_IDundefined while all the data from the records are displayed correctly? I can query it, except BUSINESS_PARTNER_ID. Does anybody know how I can fix this?
Do partnerId and objectId have values? If the values for these are there then we need to check the routing and your manifest files. If partnerId and ObjectId are blank.
If these fields are blank i can think of another fix. Instead of binding the event from table, i believe you must have a columnlistitem or objectlistitem under your table. You can assign the press event on that and move this code to that.
Basically i am triggering the event from list item instead of table.
Thanks and Regards,
Veera
"Just" change my query to
event.getParameter("listItem").getBindingContext().getProperty("XYZ");
I have a collection called customer_devices and I can't change the name. Can I expose it via deployd as /devices ? How?
There are a few ways that I can think of. If you really just want to rename the collection, you can do so from the dashboard, as #thomasb mentioned in his answer.
Alternatively, you can create a "proxy" event resource devices and forward all queries to customer_devices. For example, in devices/get.js you would say
dpd.customer_devices.get(query, function(res, err) {
if (err) cancel(err);
setResult(res);
});
Update
Finally, here is a "hack" to redirect all requests from one resource path to a different path. This is poorly tested so use at your own risk. This requires that you set up your own server as explained here. Once you have that, you can modify the routing behaviour using this snippet:
server.on('listening', function() {
var customer_devices = server.router.resources.filter(function (res) {
return res.path === '/customer_devices';
})[0];
// Make a copy of the Object's prototype
var devices = Object.create(customer_devices);
// Shallow copy the properties
devices = extend(devices, customer_devices);
// Change the routing path
devices.path = "/devices";
// Add back to routing cache
server.router.resources.push(devices);
});
This will take your customer_devices resource, copy it, change the path, and re-insert it into the cached routing table. I tested it and it works, but I won't guarantee that it's safe or a good idea...
Can't you change the name via dashboard?
Mouseover your collection customer_devices
Click the down arrow
Select 'Rename'
Enter the new name and click 'Rename'
I want to load a JSONStore based on a provided param to the adapter mapped load function.
Let me explain it better.
The JSONStore initialization is like this:
collections[EMPLOYEE_COLLECTION_NAME] = {
searchFields : {ENAME: 'string', EMPNO:'integer'},
//-- Start optional adapter metadata
adapter : {
name: 'EmployeesDB',
add: 'addEmployee',
remove: 'deleteEmployee',
replace: 'updateEmployee',
load: {
procedure: 'getEmployee',
params: [region],
key: 'resultSet'
}
}
//-- End optional adapter metadata
};
//Initialize the people collection
WL.JSONStore.init(collections, options)
As you can see in the code above, even after the param region was passed to the adapter collection init, is it supposed to change during my app life cycle, so there are moments where region let's say is SOUTH, others is NORTH and so on.
I realized that even though I change this value after the store was created, the mapped load function in the adapter getEmployee (see below) always get value that region contained at the time the jsonstore was initialized regardless I change the region variable value later on. Looks like the adapter binds conf is getting at collection creation time, and never changes it
function getEmployee(data) {
WL.Logger.info('Show param:'+data);
return WL.Server.invokeSQLStatement({
preparedStatement : selectStatement,
parameters : []
});
}
Is there a way to pass parameter to the Jsonstore load function that can change after the store was initialized ?
I wanted to avoid close and init the collection again to save time and resources.
By the way, what I really need is to have flexibility on what I load from the database based on a adapter parameter that is bound to a collection.
Try something like:
WL.JSONStore.get(EMPLOYEE_COLLECTION_NAME).adapter.load.params = ['...']
Before calling WL.JSONStore.get(EMPLOYEE_COLLECTION_NAME).load().
If you want more flexibility, you can always call WL.Client.invokeProcedure and inside the onSuccess callback you can call: WL.JSONStore.get(EMPLOYEE_COLLECTION_NAME).add(['...'], {push: false}). The push: false section will make sure JSONStore understands that the data added is up-to-date with the data on the backend. This means it won't show those documents when you call: WL.JSONStore.get(EMPLOYEE_COLLECTION_NAME).getPushRequired() or WL.JSONStore.get(EMPLOYEE_COLLECTION_NAME).push().
Hopefully, a simple question and must have a simple answer but i have wasted almost 3hrs in getting out of this issue.
I have a user model. I want to load the first user from DB and show it on first page load.
What i am trying to use is:
in my ArrayController,
init: function(){
var user = App.User.find(1)
console.log(user);
this.set('defualtUser',user.get('name'))
}
But i cant get the name of user.
Here is the output of user in console, which indicates that data is being loaded but i can't just get it to use.
Class
__ember1367188634172: "ember270"
__ember1367188634172_meta: Meta
_changesToSync: Object
_data: Object
attributes: Object
***name: "Cafe Alpino"***
__proto__: Object
belongsTo: Object
hasMany: Object
id: null
__proto__: Object
See the name: "Cafe Alpino", i just want to display this name.
Any help???
BTW, i am a newbie with EmberJS
I think the problem here is asynchronousy. This line: var user = App.User.find(1) will result in a user record that is not loaded yet; its properties aren't set until the AJAX call returns in the background. Therefore, user.get('name') will be empty.
There are probably a few ways to solve this. I haven't used Ember Data too much (since it's not very solid at the moment), but according to the docmentation, there should be a didLoad event that you can use:
init: function() {
var user = App.User.find(1);
var _this = this;
user.on('didLoad', function() {
_this.set('defaultUser', user.get('name'));
});
}
Give it a try! Let me know if it doesn't work out.