How to get html of a SAP UI5 control - sapui5

Normally when using SAP UI5, we use the following code
this.appContent.placeAt('content');
This will render the content element.
But I just want the html of appContent UI5 control without rendering it. How to do that?
The reason I want to do it is because I want to use sap.ui.template to build a carousel and I want to add get raw HTML of UI5 control and add it as a string to a template instead of rendering it directly.

Assuming this.appContent is a control, then after the contol has been rendered just call
var $domRef = this.appContent.$():
or getDomRef() (visibility is protected!)
var domRef = this.appContent.getDomRef():
Be aware when to call this after the control has been rendered, i.e. like this:
this.appContent.addEventDelegate({
onAfterRendering : function(oEvent){
var $domRef = oEvent.srcControl.$();
// now do something
}
});
this.appContent.placeAt('content');
However, I would try to avoid using placeAt.

Related

CSS from code? How to use CSS decoration directly from Vala?

How to use CSS customization directly from Vala? Not like in this example with file. Let's say I want the button to turn red by clicking on it, without using an external css file, as this action is too simple to create a css file with a single field.
I mean smth like this:
label.set_styleSheet("font-size: 17px;")
You still have to create a CssProvider, like in the code you linked to:
var screen = this.get_screen ();
var css_provider = new Gtk.CssProvider();
You can call load_from_data () instead of load_from_path () to load it from a string in memory instead of a file:
https://valadoc.org/gtk+-3.0/Gtk.CssProvider.load_from_data.html
css_provider.load_from_data(".my_class { font-size: 17px; }");
Gtk.StyleContext.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER);
When the CSS provider has loaded the custom styles to be used, you can manipulate every Gtk+ widget with get_style_context ().
The style context has methods to add, remove and query a class, etc.
https://valadoc.org/gtk+-3.0/Gtk.StyleContext.html
label.get_style_context().add_class("my_class");
Since you only have to setup the style provider once, I don't think it is too much overhead.
For anyone who is reading this I have posted both examples with and without file to Git https://gitlab.com/gavr123456789/vala-css-examples/tree/master

Aurelia - Accessing ViewModel functions/binding from within Generated DOM elements

I have a section of my view (html) that is generated programmatically by a viewmodel/class. This uses the Aurelia DOM (Aurelia Docs - pal :: Dom) functionality to generate and add the raw HTML elements to the view.
However, I am unable to get events within the generated html to call back to the viewmodel. An example:
let deleteButton = this.dom.createElement("button");
deleteButton.setAttribute("onclick", "cancelCreditNote(`${ row.creditNoteId }`)");
A click on the generated button won't call back to the viewmodel, which does have a cancelCreditNote function. Various other things like deleteButton.setAttribute("click.delegate", "cancelCreditNote('${ row.creditNoteId }')"); do not work either.
Does anyone know how to access a viewmodel class from essentiall 'raw' html in aurelia?
Unfortunately in this instance I cannot use the standard aurelia templating to generate the HTML.
The DOM property on PAL is just an abstraction for the browser's DOM object, create element is likely just calling document.createElement which doesn't afford any Aurelia binding to the created element.
You could try using aurelia.enhance(context, element) which takes an existing DOM element and runs it through the templating engine.
With this method you can also pass a binding context to apply to the element.
In my HTML I use this:
<div id="collapsesidebar" click.delegate="toggleSidebar()">
In my view-model I have this method:
toggleSidebar(){
alert('hi');
}
You could also do this from your view-model with JQuery like this:
attached() {
$('main').on('click', ()=> alert('hi'));
}
The last option is ONLY available áfter the attached() method is triggered: before that the binding needs to do its job and only after that the elements are located inside of the dom.
In other words: this will not work:
activate(){
$('main').on('click', ()=> alert('hi'));
}
because the constructor and the activate method both get fired before the attached method.

Cannot programmatically add content to simple HTML DIV Element in XML view

I have a simple XML view (fragment) like this:
<html:div id="holder"></html:div>
I want to add content programmatically like this:
var holder = this.byId("holder");
var label = new sap.m.Label({
text: "Label"
});
holder.addContent(label);
Effect is nothing, no error, no added content.
Why does it not work?
This is because content is not an aggregation (an easy mistake to make, since content usually is an aggregation).
sap.ui.core.HTML's content metadata object is a property of type string. From the jsdoc:
HTML content to be displayed, defined as a string.
You will need to use a different container for your label, such as sap.ui.layout.VerticalLayout, or you could just use raw HTML to stick in your holder object, rather than that sap.m.Label type.
Here is a jsbin that takes the XML view part of this question out of the equation.
Note: See #hirse's comment below for an important distinction when using html:div in XML views
The HTML element and the UI5 Controls are not directly compatible. UI5 Controls are JavaScript objects that have a render function. The render function creates a html fragment on demand. That html fragment ist then inserted into the page.
I have never tried it, but a solution could be to use the placeAt() method of your label:
label.placeAt("holder");
If you are using an XML View, the holder id will be prefixed. Then you should use something like this:
label.placeAt(this.getView().createId("holder"));
You can get DOM element of UI5 control by using getDomRef of sap.ui.core.Element class.
Then add your content to this DOM element by using placeAt()
Here is working example.

Titanium Classic or Alloy for Dynamic Forms

I want to develop an application which is getting form data via JSON from an external database. I need to create the form fields and its properties according this dynamic data.
It seemed to me that I need to use the classical way in Titanium instead of alloy because I think I can not add any rows dynamically on the xml (view) side in Alloy. Am I correct or is it also possible to do it in Alloy? If yes can you please tell me how
This can be done. Using this widget https://github.com/albinotonnina/it.numidia.gridWidget I was able to figure out how to create dynamic content in Alloy. Similar to the method used in this widget, I have a controller for each item I want to support. I created a textfield, textarea, label among others. It allows me to still use the Alloy styling and dynamically add the elements to my views.
Here is an example of my textfield controller:
XML
<Alloy>
<TextField id="textfield"/>
</Alloy>
js
function applyProperties(_props){
var apply = {};
_.extend(apply, _.pick(_props, 'left', 'value', 'textAlign', 'font', 'color', 'shadowOff'));
// alert(apply);
$.textfield.applyProperties(apply);
}
exports.getContent = function(){
return $.textfield.value;
};
exports.setContent = function(val){
$.textfield.value = val;
};
if(arguments[0]){
applyProperties(arguments[0]);
}
exports.applyProperties = applyProperties;
The style is completely empty since I'm using the app.tss to style this element.

How to reference dynamically added element after DOM loaded without a need to act on any events?

I know there is .on and .live (deprecated) available from JQuery, but those assume you want to attach event handlers to one ore more events of the dynamically added element which I don't. I just need to reference it so I can access some of the attributes of it.
And to be more specific, there are multiple dynamic elements like this all with class="cluster" set and each with a different value for the: title attribute, top attribute, and left attribute.
None of these jquery options work:
var allClusters = $('.cluster');
var allClusters2 = $('#map').children('.cluster');
var allClusters3 = $('#map').find('.cluster');
Again, I don't want to attach any event handlers so .on doesn't seem like the right solution even if I were to hijack it, add a bogus event, a doNothing handler, and then just reference my attributes.
There's got to be a better solution. Any ideas?
UPDATE:
I mis-stated the title as I meant to say that the elements were dynamically added to the DOM, but not through JQuery. Title updated.
I figured it out. The elements weren't showing up because the DOM hadn't been updated yet.
I'm working with Google Maps and MarkerClustererPlus to give some more context, and when I add the map markers using markerclustererplus, they weren't available in the javascript code following the add.
Adding a google maps event listener to my google map fixed the problem:
google.maps.event.addListener(myMarkerClusterer, 'clusteringend', function () {
// access newly added DOM elements here
});
Once I add that listener, all the above JQuery selectors and/or methods work just fine:
var allClusters = $('.cluster');
var allClusters3 = $('#map').find('.cluster');
Although this one didn't, but that's because it only finds direct decendants of parent:
var allClusters2 = $('#map').children('.cluster');
Do what you need to do in the ajax callback:
$.ajax(...).done(function (html) {
//append here
allClusters = $('.cluster');
});
If you want them to be separate, you can always bind handlers after the fact, or use $.when:
jqxhr = $.ajax(...).done(function (html) { /* append html */ });
jqxhr.done(function () { allClusters = $('.cluster') });
$.when(jqxhr).done(function () { /* you get it */ });
If these are being appended without ajax changes, then just move the cluster-finding code to wherever the DOM changes take place.
If that's not an option, then I guess you would just have to check on an interval.