Get property data from outer context - jquery-templates

I am trying to access the parent data from a nested template.
According to this https://github.com/BorisMoore/jsrender/issues/34, I am trying to do somehing similar but I am getting Error: data.parent is undefined.
In my 'master' template I have the declaration
{{for Rooms tmpl="#RoomTmpl" layout=true /}}
and in the #RoomTmpl
<script id="RoomTmpl" type="text/x-jsrender">
{{:parent.data.Room1Label}}
{{for #data}}
{{:RoomName}}
{{/for}}
</script>
I tried various combinations but always I get an error
{{:parent.parent.data.Room1Label}}
{{:#data.parent.parent.data.Room1Label}}
{{:#data.parent.data.Room1Label}}
{{:#data.parent.Room1Label}}
Does anyone knows how to do this?
-- SOLUTION --
the correct synatx is
#parent.parent.data.Room1Label

You want to step up through the views and get the data from a parent view. A view is the result of rendering a template, and so nested block tags, such as {{for...}}...{{/for}} or {{if...}}...{{/if}} will add child views. If you pass an array to a 'for' tag, {{for myArray}}, it will iterate over the data array and it leads to one child view whose data property is the array, and that view will then have collection of child views for each rendered item.
So you need to know that #view is the view, #view.parent is the parent view, #view.parent.data is the parent view's data etc. #foo is short for #view.foo, so #data is the data, #parent the parent view etc.
Now the only issue is to count the number of parents correctly. You can debug into what is going on by adding a method to your data: { ... properties ..., test: function() {debugger;} }. Now add {{:test()}} anywhere in a template for that data item, and step into the compiled temmplate: look at the view, its parents etc.
Another trick. If you set a template variable on any block tag, you can then access it from any nested template. So In your example, you can put
{{for Rooms tmpl="#RoomTmpl" ~label=Room1Label layout=true /}}
and then access it from a nested template as:
{{:~label}}
That way you no longer need to worry about stepping up through the parent views.

Related

How to retrieve the rows which are selected in the list report page of smart templates

This is the List Report type of Smart Template application
Here I have selected 2nd and 5th row, I also have a button named Send Requests in the section part which is highlighted. If I click this button it calls a javascript controller function which is defined in the extensions of the application. In this js function how can I retrieve the selected rows that are selected?
I have enabled the checkboxes in this page by mentioning this code
"settings": { "gridTable": false, "multiSelect": true } in the manifest.json
As it was recommended by this link https://sapui5.netweaver.ondemand.com/#docs/guide/116b5d82e8c545e2a56e1b51b8b0a9bd.html
I want to know how can I retrieve the rows which got selected?
There is an API that you can use for your use case. It is described here: https://sapui5.netweaver.ondemand.com/#docs/guide/bd2994b69ef542998becbc69ab093f7e.html
Basically, you just need to call the getSelectedContexts method. Unfortunately you will not be able to really get the items themselves, only the binding contexts (which point to the data entities which are selected). Excerpt from the documentation:
After you have defined a view extension, you can access and modify the
properties of all UI elements defined within these extensions (for
example, change the visibility). However, you cannot access any UI
elements that are not defined within your view extensions.
In this type of table there is way.
var myTable=sap.ui.getCore().byId("your table id");
get all rows:
var myTableRows=myTable.getRows();
now get selected Indices
var selectedIndeices=myTable.getSelectedIndices(); //this will give you array of indeices.
now run loop on indeices array. And get particular row item;
// get binding path
var bindingpath=myTableRows[2].getBindingContext().sPath; // this will return eg:"/ProductCollection/2"
// now get Binding object of that particular row.
var myData=myTableRows[2].getModel().getObject(bindingpath); // this will return binding object at that perticular row.
// once your loop is over in the end you will have all object of selected row. then do whatever you want to do.
If you use smart template create an extension.
This is the standard event befor the table is rebinding:
onBeforeRebindTableExtension: function (oEvent) {
this._table = oEvent.getSource().getTable();
}
In your action function (or where you want) call the table and get the context :
this._table.getSelectedContexts();

Angular2 model-based parent/children form

I'm a newbie with Angular2 (beta1) and I'd like to implement a sort of simple editable grid, built of 2 components. Here I use two fake-data components to keep things simple. They are (see this Plunker: http://plnkr.co/edit/5cZfLTIlhLc82wWV4PQI):
the parent component, named contact. Say it represents a contact with a name.
the child component, named entry. Say it represents an entry for a contact, where each contact can include 0 or more entries. Each entry has an address and a zip code.
I'd like to create a form where the user can edit the contact's properties, and also its children entries: he could add a new entry, delete an existing entry, or edit an existing entry.
To this end, the views for both these components provide a form-based template.
I can think of this data flow:
contact: the user edits the form and then clicks a submit button to save
the whole thing. Thus, I can just have some code handling the submit button
and emitting an event as the component output. The contact has an entries
array property: I can thus use an ngFor directive in its template to render
an entry component for each of them.
entry: the entry has properties addressCtl and zipCtl which represent
the control directives included in the ControlGroup representing the whole
form. Also, I need a couple of properties to be bound as the input of the
component (address and zip), so that in the parent template I can do something like:
<tr *ngFor="#e of entries">
<td><my-entry [address]="e.address" [zip]="e.zip"></my-entry></td>
</tr>
Now, it's not clear to me how to shape the relation between the "model" properties representing the control's input, and the "form" directives properties. I should be able to get the address and zip values from the parent component through the [...] binding, and pass the updated values up through an event fired by the child component (e.g. blur?). Does this make sense in the NG2 world? Anyway, I'm missing a piece here: how can I connect the form controls values to the model properties values? Could anyone make this clearer or point to some good docs?
In fact, using the [...] binding only corresponds to a one-way binding. When the parent property is updated in the parent component, the value is also updated in the child component.
But if you want to update parent attributes from the child, you need to leverage events and #Ouput attribute.
Here is a sample with a labels component:
export class LabelsComponent implements OnInit {
#Input()
labels:string[];
#Output()
labelsChange: EventEmitter;
(...)
removeLabel(label:string) {
var index = this.labels.indexOf(label, 0);
if (index != undefined) {
this.labels.splice(index, 1);
this.labelsChange.emit(this.labels);
}
}
addLabel(label:string) {
this.labels.push(this.labelToAdd);
this.labelsChange.emit(this.labels);
this.labelToAdd = '';
this.addAreaDisplayed = false;
}
}
This way you can leverage two way binding on this component:
<labels [(labels)]="company.labels"></labels>
Hope it answers your question,
Thierry
Just moved the comment to answer...
You can pass the object e, instead of passing string.
i.e
<my-entry [entry] = "e"></my-entry>
then in your my-entry component, use ng-model for each input. so you automatically gets 2 way bindings.

Is it possible to have XML Fragments IDs prefixed with its view's ID?

When a XML view is declared, all of its controls IDs are prefixed by the ID of the view itself.
In order to get any control inside the controller it's necessary to use:
this.byId()
... where this points to the controller by default.
I already know that there is
sap.ui.getCore().byId()
as well which can be used to retrieve a control defined in a JS View or created without a view prefix.
I declared a XML fragment with a dialog and a Text control which will contain a text defined by my controller. I noticed that the ID I defined inside the fragment is not prefixed with the view's ID.
My question is: Is it possible to have XML Fragments IDs prefixed with its view's ID (then I could use this.byId instead of sap.ui.getCore) ?
I checked and this appears to be happening only when you are adding the fragment from a controller. If the fragment is defined in the static time in the xml view the ID's of the content derive their name from the view.
The way to get over this is to ensure your fragment ID is derived from your view.
The code would be something like this in your controller.
oPage.addContent(new sap.ui.xmlfragment(this.createId("idFragment"), "fragmentcreation.SampleFragment"));
IdFragment = ID for your fragment
fragmentcreation.SampleFragment = Name of your fragment(fragmentcreation is the folder)

JsViews/JsRender temporary/contextual helper variable in for loop

I'm trying to store a temporary/contextual variable in a for loop for later use inside another for loop. I used http://borismoore.github.io/jsrender/demos/step-by-step/11_accessing-parent-data.html as a reference.
{^{for instances ~templateId=templateId}}
{{:~templateId}}
<select data-link="templateId" class="selected-visible" name="select-template">
{^{for ~root.templates}}
<option data-link="{:name} value{:id} selected{:id == ~templateId}"></option>
{{/for}}
</select>
{{/for}}
Each data object in the instances array has a templateId property that is set to a certain value and each object in the templates array has an id property.
The first problem is that my debug {{:~templateId}} is not showing up. It seems the variable is not assigned.
After only using the ~helper set within the template markup, I have tried explicitly defining the helper in my "viewmodel" with
$.views.helpers({templateId: 0});
Now the value gets printed when I do not set it in the for loop, but when I set it in the for loop it disappears again.
The next problem might be that the ~templateId helper is not available in a ~root-scoped for loop, because the helper should only be available in child views of the instances loop?
The ultimate goal is to select the correct value in the select, so if other solutions are available, please do tell.
You need to remove ~templateId=templateId from your template...
Explanation:
The syntax ~helper is used to access helpers/contextual parameters, which can be either be passed in/registered externally, as shown here http://www.jsviews.com/#helpers, or can be created/set within a template, as in the example you linked to {{for movies ~theater=theater}} , or in this one: ~frstNm=firstName: http://www.jsviews.com/#samples/jsr/paths.
So generally you will either pass a helper in, or create it within the template - not both.
In your example above you are first passing ~templateId in - as 0 - and then you are redefining it as a contextual parameter, using ~templateId=templateId (which is actually setting its value to undefined, since ...=templateId sets it to the value of the templateId property of the current data - undefined, in your case).

Prevent creating DOM element in the controller and use view instead

As you may know Spine controllers create their DOM elements ( <div> by default ).
How could we prevent creating such elements and use only markup in the view?
I read the documentation but didn't find any information.
The relevant line is https://github.com/spine/spine/blob/dev/src/spine.coffee#L488, which says:
#el = document.createElement(#tag) unless #el
In order to avoid having the element be created, you can pass in an el to the constructor. Alternatively, you can call #replace() in your render method to replace the div with your own element.