Bind "one to many" OData association to aggregation in UI5 - data-binding

I'm reading some data from a OData service. Within the controller, I do the following:
this.getView().bindElement({
path: "/HeaderData(key1='key1',key2='key2')",
parameters: { expand: 'toItems' }
});
The data is read correctly and the model within the console looks like:
HeaderData(key1='key1',key2='key2'): {
HeaderField1: "value1"
HeaderField2: "value2"
toItems: {__list: Array(2)}
}
Now, I want to bind the entries within the "toItems" collection to a table.
I've tried the following but it's not working because "toItems" is a collection.
<Table items="{
path: '/HeaderData',
parameters: { expand: 'toItems' }
}">
This one is also not working:
<Table items="{
path: '/HeaderData/toItems'
}">
How to bind the items correctly? The table could not be accessed via ID, so the binding must be within the XML view.

Simply bind the navigation property to the aggregation:
<Table items="{toItems}">
Make sure to omit / at the beginning of the binding path since it's supposed to be resolved relative to the bound entity / context (that was given by bindElement). To learn more, see topic Binding Path.
The ODataListBinding will then send a request to the items accordingly if they're not available already.

Related

What is the best way to extract component information that is intersected with raycaster?

Is there any way to extract the entity's information(id, class, etc) that is intersected with a raycaster?
I tried to find the information from evt.detail.el but no success.
AFRAME.registerComponent('collider-check', {
init: function () {
this.el.addEventListener('raycaster-intersected', function (evt) {
console.log(evt.detail.el);
});
}
});
The issue is that the code above logs the raycasting entity, rather than the raycasted entity, so it is logging the cursor.
Using the code above, you can access the data you need by logging evt.detail.intersection.object.el. So you could do something like the following to access id and class, respectively:
console.log(evt.detail.intersection.object.el.id);
console.log(evt.detail.intersection.object.el.className);
Here is a demo of the code in action: https://codepen.io/dansinni/pen/bjjbWv
If you haven't bound this to the handler, and only need basic attribute data, you should also be able to do the following, but YMMV:
console.log(this.id);
console.log(this.className);
You should also be able to use a component with the cursor instead, and rely on the raycaster-intersection event. Note the difference in the docs: https://aframe.io/docs/master/components/raycaster.html#events

Meteor JS Routing on Angular 2 Tutorial doesn't work

I'm trying to make the socially tutorial from the meteor js web but I'm stuck on the step 5 Routing & Multiple Views
When I click on the link to see "party details" the javascript console says that the route doesn't exists.
This is the code from the view that has the link.
<a [routerLink]="['/party', party._id]">{{party.name}}</a>
And this is the code from the routes:
const routes: RouterConfig = [
{ path: '', component: PartiesListComponent },
{ path: 'party/:partyId', component: PartyDetailsComponent }
];
This is the output from the console.
browser_adapter.js:84 EXCEPTION: Error: Uncaught (in promise): Error: Cannot match any routes: 'party;_str=57df4efc74ee85f397a687f3'
The most likely reason for this is that party._id is actually an object, not the id primitive. If I had to put my money on it, I'd say this it what it looks like
party: {
_id: {
_str: '57df4efc74ee85f397a687f3'
}
}
When you add an object into the routerLink array, it becomes a matrix parameter for the previous path segment. So if the above is the actual structure, then would result in
/party;_str=57df4efc74ee85f397a687f3
which is the problem you are facing. If you want to just add the id value to the path, then you should extract the _str
<a [routerLink]="['/party', party._id._str]">
This will give you the route
/party/57df4efc74ee85f397a687f3
which is what you want.
See Also:
Angular docs on Route Parameters

Angular ui-router setup for this use case?

I want to redraw a line in a line chart without reloading it (neither template nor controller) completely when navigating from country/5 to country/7. Can this be done with ui-router?
State
country/:id
Template with directive - country.html
<lineChart data="scope.someData">
Controller
onStateParamsChange => fetch data, set scope.someData
As of today, there is no official support for what you're looking for, which in UI Router parlance is considered 'dynamic parameters'. However, if you check out this experimental branch and help us out by testing and providing feedback, it will get merged to master sooner.
Set up your route/state like so:
$stateProvider.state("country", {
url: "/country/{id:int}",
params: { id: { dynamic: true } }
/* other state configuration here */
});
Then, in your controller, you can observe changes to id like so:
$stateParams.$observe("id", function(val) {
// val is the updated value of $stateParams.id
// Here's where you can do your logic to fetch new data & update $scope
});

EmberJS View programmatically using a not loaded model

I have a model:
App.Checkin = DS.Model.extend({
latitude: DS.attr('string'),
longitude: DS.attr('string'),
time: DS.attr('number')
});
And a route that loads the collection of checkin models (making a request with ember-data) by
model: function() {
return this.store.find('checkin');
}
And then in the template for the route I have
{{view App.MapView}}
And I need to access the model programmatically so that I can iterate over each item in the model to add a pin to the map.
Inside my view I have
didInsertElement: function() {
var data = this.get("context.content");
}
and data is
Class {type: function, store: Class, isLoaded: true, isUpdating: true, toString: function…}
In the network window, the request to the server hasn't completed by that point, so it obviously wouldn't have data to provide. (Even if it did, I don't know how to query an object like that, none of the expected methods worked (get/forEach))
I believe that I need to observe the model being changed, and have tried
updatePins: function() {
debugger;
}.observes('context.content')
inside of the view. I have tried binding to all sorts of things, but reRender has never been called. I've tried the recommendations on Emberjs view binding for Google maps markers
by trying to bind to controller.content, context, App.Checkin, etc.
How do I go about getting the data from the model once it has loaded...inside of the view?
Until the model does not resolve what you get is a promise for that model, obviously the promise does not contain the data just yet but when the request comes back from the server. You could check in your template if the model has data, by observing the model.length property for example using an if helper, the if helper block will re-evaluate when the length property changes this beeing when it has received data.
For example, you could try something like this:
...
{{#if model.length}}
{{view App.MapView}}
{{/if}}
...
This will ensure that your App.MapView is then rendered when your model has data and therefore you will have also access to the data in the view's didInsertElement hook as you'd expect.
Update
Your reRender hook is named slightly wrong, it should be rerender
rerender: function() {
debugger;
}.observes('context.content')
Hope it helps.

can I bind a value to a part of an object from elsewhere in the model?

I have a model that has (for example) shopping cart item IDs and a list of available items to add to the cart. It's a fake example.
table#items
tbody
tr(ng-repeat="item in cart.items")
td.hide {{item.id}}
td {{availableItems.where(id: item.id).first.name}} <-- pseudo code
td ({{item.shippingType}})
What I'd like to do is bind the second cell to the name of the item from the list of available items, rather than cluttering up the model by having that value in 2 places. Would I use a filter function to do this? The docs are very simplistic. How can I pass item.id to the filter function?
I've gotten closer with this in the markup:
td {{availableDatasources | filter: itemNameById}}
and this in the scope:
$scope.itemNameById= function(item) {
lodash($scope.availableItems).find({
id: item.id
}).name;
};
Only problem is I don't get a name back (even though that's what the filter seems to be returning) -- I get all of the available items. It's hitting the filter code but the filter seems to not be filtering.
Honestly, I'm not sure this is worthwhile. Your cart is probably just an array of references to objects in your availableItems array, so you're not really repeating anything.
But if I wanted to do as you say, I would include underscore.js in my project.
http://underscorejs.org/
Then in the controller, I would add underscore to the scope:
$scope._ = _;
In my template I would write
td {{_.findWhere(availableItems, {id: item.id}).name}}
Or, more likely, I would add a more specific function to my scope:
$scope.productFromId =
function(id) { return _.findWhere($scope.availableItems, {id: id});};
And then in the template:
td {{productFromId(item.id).name}}

Resources