How can I dynamically create HTML components in Marko? - dom

I want to create new Marko components every time the user clicks a button — by calling something like the JavaScript DOM method document.createElement("tag"). How can I do this in Marko, not just with ordinary HTML tags, but with custom Marko tags?
What I tried: document.createElement("custom-marko-component")
Expected behavior: Marko engine compiles a new instance of the custom component.
Actual behavior: The browser makes a useless new <custom-marko-component></custom-marko-component>.

Use Marko's rendering functions (documentation: https://markojs.com/docs/rendering/):
Example:
// Create the custom component, like document.createElement() but asynchronous.
// Import `./custom-marko-component.marko`
var customComponent = require("./custom-marko-component");
var resultPromise = customComponent.render({});
// Insert the custom component into the webpage.
resultPromise.then(result => {
result.appendTo(document.body);
});

Related

How to access control from the popup fragment by ID

I want my text area to be empty after I press OK button.
I have try this line this.byId("id").setValue("")
onWorkInProgress: function (oEvent) {
if (!this._oOnWorkInProgressDialog) {
this._oOnWorkInProgressDialog = sap.ui.xmlfragment("WIPworklist", "com.sap.FinalAssestments.view.WorkInProgress", this);
//this.byId("WIP").value = "";
//this.byId("WIP").setValue();
this.getView().addDependent(this._oOnWorkInProgressDialog);
}
var bindingPath = oEvent.getSource().getBindingContext().getPath();
this._oOnWorkInProgressDialog.bindElement(bindingPath);
this._oOnWorkInProgressDialog.open();
},
//function when cancel button inside the fragments is triggered
onCancelApproval: function() {
this._oOnWorkInProgressDialog.close();
},
//function when approval button inside the fragments is triggered
onWIPApproval: function() {
this._oOnWorkInProgressDialog.close();
var message = this.getView().getModel("i18n").getResourceBundle().getText("wipSuccess");
MessageToast.show(message);
},
The text area will be in popup in the fragment. I am expecting the text area to be empty.
If you instantiate your fragment like this:
sap.ui.xmlfragment("WIPworklist", "com.sap.FinalAssestments.view.WorkInProgress", this);
You can access its controls like this:
Fragment.byId("WIPworklist", "WIP").setValue(""); // Fragment required from "sap/ui/core/Fragment"
Source: How to Access Elements from XML Fragment by ID
The better approach would be to use a view model. The model should have a property textAreaValue or something like that.
Then bind that property to your TextArea (<TextArea value="{view>/textAreaValue}" />). If you change the value using code (e.g. this.getView().getModel("view").setProperty("/textAreaValue", "")), it will automatically show the new value in your popup.
And it works both ways: if a user changes the text, it will be automatically updated in the view model, so you can access the new value using this.getView().getModel("view").getProperty("/textAreaValue");.
You almost have it, I think. Just put the
this.byId("WIP").setValue("") line after the if() block. Since you are adding the fragment as a dependent of your view, this.byId("WIP") will find the control with id "WIP" every time you open the WIP fragment and set its value to blank.
You are likely not achieving it now because A. it is not yet a dependent of your view and B. it is only getting fired on the first go-around.

In AEM6, How do I hide a specific component field based on pages for certain country only?

In AEM6, How do I hide a specific component field based on pages for certain country only ?
You can write custom dialog/widget plugin to do that. This is how you attach plugin to your widget:
<title jcr:primaryType="cq:Widget"
fieldLabel="Field to hide"
plugins="hideFieldPlugin"
name="./fieldToHide"
xtype="textfield" />
Next, we need to write plugin and register it:
(function ($) {
var plugin = CQ.Ext.extend(CQ.Ext.emptyFn, {
init: function (fieldToHide) {
var url = CQ.HTTP.getPath();
if (this.shouldBeHidden(url)) {
fieldToHide.hide().disable();
}
},
shouldBeHidden: function (url) {
// some logic
return true;
}
});
CQ.Ext.ComponentMgr.registerPlugin("hideFieldPlugin", plugin);
}($CQ));
JavaScript file needs to be included in Classic UI edit mode. Best way to do that is to use your own custom clientlib or use already existing category, cq.wcm.edit.
If you have more complex logic which goes across multiple widgets, you can attach plugin on dialog level and navigate to the widget objects using dialog.find method.

Inject css stylesheet in GWT RichTextArea head

is it possible to inject a stylesheet into the head of a GWT RichTextArea
Seems as if i place a style element in the body, some browser e.g. IE7 allows the user to delete the node.
I had the same problem, here's the solution to add in the class constructor:
richTextArea.addInitializeHandler(new InitializeHandler() {
public void onInitialize(InitializeEvent ie) {
document = IFrameElement.as(richTextArea.getElement()).getContentDocument();
StyleElement se = document.createStyleElement();
se.setType("text/css");
se.setInnerHTML("some CSS");
BodyElement body = document.getBody();
body.getParentNode().getChild(0).appendChild(se);
}
});
StlyeInjector can directly insert CSS if you don't want to use a CSS file. It gets put into the head as far as I can tell, but for the whole document.
Yes it is. But you need a library like gwtquery to manipulate the dom, or code some jsni.
I'd rather gquery because of its simplicity and it will work with all browsers.
import static com.google.gwt.query.client.GQuery.*;
// First attach the widget to the DOM
RootPanel.get().add(richTextArea);
// We only can manipulate the head, once the iframe document has been created,
// and this happens after it has been attached.
// Because richtTextArea uses a timeout to initialize we need a delay.
$(richTextArea).delay(1,
lazy()
.contents()
.find("head")
.append("<style> body{background: red} </style>")
.done());
With GWT + JSNI you have to do something like this (not tested in all browsers though):
// First attach the widget to the DOM
RootPanel.get().add(richTextArea);
// We only can manipulate the head, once the iframe document has been created,
// and this happens after it has been attached.
// Using a timer because richtTextArea uses a timeout to initialize.
Timer insertCss = new Timer() {
private native Element getHeadElement(Element iframe) /*-{
return iframe.contentWindow.document.head;
}-*/;
public void run() {
Element head = getHeadElement(richTextArea.getElement());
Element style = DOM.createElement("style");
style.setInnerText("body{background: yellow}");
head.appendChild(style);
}
};
// Schedule the timer
insertCss.schedule(1);

In ember, how do I pass view data from a drag into a drop?

I'm using ember latest and jquery.ui's Draggable and Droppable. I am also using some mixins that a talented ember person created to make a Draggable and Droppable view in ember. Here's the fiddle:
http://jsfiddle.net/inconduit/6n49N/7/
I need to attach the view's content to the drag event so that I can access it in the drop event. With straight up jquery, I know you'd do $(..).draggable({ .. }).data("myData","some data here"); but I don't know how to reference the view's content in this ember implementation.
Here's a snippet from App.Draggable in the fiddle:
App.Draggable = JQ.Draggable.extend({
appendTo: 'body',
helper: function() {
$(this).data("myData","this is where actual data would go");
JQ.Draggable extends Ember.View. Inside the helper() function, 'this' refers to the actual DOM element, I don't know how to refer to the View's variables. I want to pass the view's content so that it can be retrieved here:
App.Droppable = JQ.Droppable.extend({
drop: function(event,ui) {
alert('Dropped! ' + $(ui.draggable).data("myData"));
The template for the draggable looks like this:
{{#view App.Draggable contentBinding="App.anObject"}}Drag me{{/view}}
and I would like to pass that content. Please have a look at the fiddle, the pertinent functions are defined at the bottom of the javascript.
answering my own question here.
i attached the data in the didInsertElement callback as follows:
App.DraggableDataView = App.Draggable.extend({
didInsertElement: function() {
this._super();
var element = this.get('element');
$(element).data('myData',this.get('content'));
},
});

Create jQuery ui resizable instance using selector added to DOM by jQuery

I'm trying to start a jquery ui resizable instance, but using a selector added to the DOM by jquery itself. This is a basic example of my script:
HTML:
<div class='lyr'></div>
jQuery:
// Add class
$('lyr').addClass('fixed');
// Resizable
$('.fixed').resizable({
aspectRatio: true,
handles: 'all'
});
I've thought about using something along the lines of live() or bind() but I have no event to bind to. Any help appreciated.
I have used the LiveQuery plugin - http://brandonaaron.net/code/livequery/docs in the past to be able to target elements added to the dom, like in your case.
If I've got this right, you want anything on the page which has the class "fixed" to be resizable, even if the class is added after the page has loaded? You're right that live, bind and delegate won't help here.
I can think of two possibilities, neither lovely.
First, set up a live "mouseenter" event which will make the element resizable if it wasn't before:
$(body).delegate(".fixed", "mouseenter", function(ev) {
var target = $(ev.target);
if (target.data("resizable")) return;
target.resizable({
aspectRatio: true,
handles: 'all'
});
})
This gets us round the problem of having no event to bind to.
Alternatively, you could monkeypatch jQuery.fn.addClass:
var classRe = new RegExp(c + className + \b);
._addClass = jQuery.fn.addClass;
jQuery.fn.addClass = function(className) {
if (classRe.test(classname)) {
if (this.data("resizable")) return;
this.resizable({
aspectRatio: true,
handles: 'all'
});
}
jQuery.fn._addClass.apply(this, arguments);
}
Of course this will only work if the class is added through the addClass method.
Also in your example,
$('lyr').addClass('fixed');
Should probably be:
$('.lyr').addClass('fixed');