I'm trying to create a new Custom Component in pentaho. It is just a menu for every dashboard that I need to use, with some buttons and a text input.
I have in my solutions/system/pentaho-cdf-dd/resources/custom/components my ControlComponent folder, with component.xml and control-implementation.js. I have too in amd-components, the same folder but with ControlComponent.js.
In CDE, I can use it, but every time I run my dashboard, come the error from javascript.
define(['cdf/components/BaseComponent', 'cdf/lib/jquery'],
function(BaseComponent, $) {
return BaseComponent.extend({
update: function() {
if(this.htmlObject){
var ph = $("#" + this.htmlObject);
} else{
var ph = $("<div id='ControlDefault'></div>").appendTo("body");
}
var content = '<div id="Control" class="row clearfix">'+
'<div class="col-xs-6-last">'+
'<div>'+
'<div class="row clearfix">'+
'<div class="col-xs-1">'+
'<div id="Left" title="left">'+
+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</div>';
ph.append(content);
}
});
});
The error is:
require.js:8 Uncaught Error: Script error for:
cde/components/ControlComponent
http://requirejs.org/docs/errors.html#scripterror
at C (require.js:8)
at HTMLScriptElement.onScriptError (require.js:30)
Thanks in advance.
Check that the tag in component.xml is named controlComponent to match your js file name. RequireJS uses the IName tag value to reference the js file name instead of the Code tag src attribute.
Also, the Implementation tag needs attribute supportsAMD="true".
Related
I'm trying to use Twitter's typeahead.js in a Vue component, but although I have it set up correctly as tested out outside any Vue component, when used within a component, no suggestions appear, and no errors are written to the console. It is simply as if it is not there. This is my typeahead setup code:
var codes = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('code'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: contextPath + "/product/codes"
});
$('.typeahead').typeahead({
hint: true,
highlight: true,
minLength: 3
},
{
name: 'codes',
display: 'code',
source: codes,
templates: {
suggestion: (data)=> {
return '<div><strong>' + data.code + '</strong> - ' + data.name + '</div>';
}
}
});
I use it with this form input:
<form>
<input id="item" ref="ttinput" autocomplete="off" placeholder="Enter code" name="item" type="text" class="typeahead"/>
</form>
As mentioned, if I move this to a div outside Vue.js control, and put the Javascript in a document ready block, it works just fine, a properly formatted set of suggestions appears as soon as 3 characters are input in the field. If, however, I put the Javascript in the mounted() for the component (or alternatively in a watch, I've tried both), no typeahead functionality kicks in (i.e., nothing happens after typing in 3 characters), although the Bloodhound prefetch call is made. For the life of me I can't see what the difference is.
Any suggestions as to where to look would be appreciated.
LATER: I've managed to get it to appear by putting the typeahead initialization code in the updated event (instead of mounted or watch). It must have been some problem with the DOM not being in the right state. I have some formatting issues but at least I can move on now.
The correct place to initialize Twitter Typeahead/Bloodhound is in the mounted() hook since thats when the DOM is completely built. (Ref)
Find below the relevant snippet: (Source: https://digitalfortress.tech/js/using-twitter-typeahead-with-vuejs/)
mounted() {
// configure datasource for the suggestions (i.e. Bloodhound)
this.suggestions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('title'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
identify: item => item.id,
remote: {
url: http://example.com/search + '/%QUERY',
wildcard: '%QUERY'
}
});
// get the input element and init typeahead on it
let inputEl = $('.globalSearchInput input');
inputEl.typeahead(
{
minLength: 1,
highlight: true,
},
{
name: 'suggestions',
source: this.suggestions,
limit: 5,
display: item => item.title,
templates: {
suggestion: data => `${data.title}`;
}
}
);
}
You can also find a working example: https://gospelmusic.io/
and a Reference Tutorial to integrate twitter typeahead with your VueJS app.
I'm using w2ui grid, and the template column generated like so:
{ field: 'TableCards', caption: 'Table cards', size: '10%', sortable: true ,
render:function(record, index, column_index) {
let html = '';
if (record.TableCards) {
record.TableCards.forEach(function(card) {
html += `<div class="card-holder" style="width: 12%; display: inline-block; padding: 0.5%;">
<div class="poker-card blah" poker-card data-value="${card.value}"
data-color="${card.color}"
data-suit="&${card.suit};"
style="width: 30px;height: 30px">
</div>
</div>`;
});
}
return html;
}
},
poker-card as u can see is a custom attribute. and it's not get rendered in the grid.
any other way?
You can use the TemplatingEngine.enhance() on your dynamic HTML.
See this article for a complete example: http://ilikekillnerds.com/2016/01/enhancing-at-will-using-aurelias-templating-engine-enhance-api/
Important note: based on how your custom attribute is implemented, you may need to call the View's lifecycle hooks such as .attached()
This happened to me, when using library aurelia-material, with their attribute mdl.
See this source where the MDLCustomAttribute is implemented, and now see the following snippet, which shows what I needed to do in order for the mdl attribute to work properly with dynamic HTML:
private _enhanceElements = (elems) => {
for (let elem of elems) {
let elemView = this._templEngine.enhance({ element: elem, bindingContext: this});
//we will now call the View's lifecycle hooks to ensure proper behaviors...
elemView.bind(this);
elemView.attached();
//if we wouldn't do this, for example MDL attribute wouldn't work, because it listens to .attached()
//see https://github.com/redpelicans/aurelia-material/blob/5d3129344e50c0fb6c71ea671973dcceea14c685/src/mdl.js#L107
}
}
This is my object
var users ={
twitter : {
name : //,
lastname : //
},
facebook : {
name : //,
lastname : //
}
}
}
I have a dynamic variable activeuser that updates from Facebook to twitter.
What i'm trying to do is refer to the inner object in users depending on the value of activeuser. I need to give my div something like this class :
<div class=' {{users.activeuser}}'></div>
I know this is not how it should be done with vue.js. Do you have any suggestions?
Thank You!
Using VueJS you should be able to assign your dynamic variable to a Vue Model when you load the new object using a Vue setter $set('property name', 'value')
Example AJAX retreival:
$.getJSON('myURL.html?query=xxx', function(data, textStatus, jqXHR){
try{
MyVue.$set('dynamicObject', data);
}
catch(e){}
});
A generic Vue may look like this:
var MyVue = new Vue({
el:'#exampleDiv',
data: {
dynamicObject : ''
}
});
Bound to an example HTML element:
<div id="exampleDiv">
<label class="{{dynamicObject.activeuser}}">{{dynamicObject.username}}</label>
</div>
In the case that you have an object with an array of objects which also contain properties Vue makes it very simple to create many HTML elements (for each child object) by simply adding a v-repeat (example) to the desired HTML and assigning the datasource:
<div id="exampleDiv">
<label v-repeat="dynamicObject" class="{{dynamicObject.activeuser}}"></label>
</div>
I have an XTemplate and I would like to add some actual EXT widgets inside the template so that I have template code rendered above and below the widgets. Let's say I have a "dataview" with the following itemTpl defined:
itemTpl: [
'<tpl for=".">',
'<div class="song-page-header">',
' <div class="artwork"><img src="{artwork}"/></div>',
' <h1>{title}</h1>',
' <h2>{artist}</h2>',
' <h3>Genre: {genre}</h3>',
' <p>{copyright}</p>',
'</div>',
/* Ext.Button should go here */
'<tpl for="offers">',
' <p>{offer_id}: {offer_type}, {price}</p>',
'</tpl>',
'</tpl>'
]
Is it possible to define a real Ext.Button there (and not just some HTML approximating the behavior of an Ext.Button)? I don't care if it has to be applied after the fact, but I can't seem to find the correct event handler to use to be able to insert a button there. The Sencha documentation sucks so any help would be greater appreciated.
Actually you can do this, you just have to be a little bit creative.
Check out my blog post here: http://jakes-hackerblog.herokuapp.com/blog/2013/05/23/a-fresh-rails-blog/
Essentially, you put some dynamic div element in your template
'<div id="box-holder">' +
'<div id="box-{schoolpersonid}"></div>'+
'</div>'+
Then you use the use "renderTo" within your button config, calling it in a refresh funciton:
listeners: {
'refresh': function(records) {
var storeRecords = records._store._data.items;
for(var i = 0; i < storeRecords.length; i++){
var data = storeRecords[i].data;
var renderTo = this.element.select('#box-' + data.schoolpersonid).elements[0];
var button1 = new Ext.Button({
action: 'doPresent',
xtype: 'button',
align: 'right',
text: 'Present',
ui: 'present',
renderTo: renderTo,
schoolpersonid: data.schoolpersonid
});
}
}
},
I think XTemplate does not support this feature due to managment and performance of Sencha Touch framework.
Secondly, you cannot do like that because basically you're trying to merge between HTML and javascript inside your itemTpl when sencha template only allow html structure.
In order to address this scenario, you may take a look at Component Dataview
<div dojoType="dojo.Dialog" id="alarmCatDialog" bgColor="#FFFFFF" bgOpacity="0.4" toggle="standard">
<div class='dijitInline'>
<input type='input' class='dateWidgetInput' dojoAttachPoint='numberOfDateNode' selected="true">
</div>
how to show this dialog I tried dijit.byId('alarmCatDialog').show();
The above code is a template and I called dijit.byId('alarmCatDialog').show() from the .js file .
dojo.attr(this.numberOfDateNode) this code works and I got the data .but if I change dojoattachpoint to id then I try dijit.byId('numberOfDateNode') will not work;
Your numberOfDateNode is a plain DOM node, not a widget/dijit, i.e. javascript object extending dijit/_Widget, which is the reason you cannot get a reference to it via dijit.byId("numberOfDateNode"). Use dojo.byId("numberOfDateNode") instead and you are all set.
dojoAttachPoint or its HTML5 valid version data-dojo-attach-point is being used inside a dijit template to attach a reference to DOM node or child dijit to dijit javascript object, which is the reason dijit.byId('alarmCatDialog').numberOfDateNode has a reference to your <input type='input' class='dateWidgetInput' .../>.
The main reason to use data-dojo-attach-point is that:
you can create multiple instances of dijit and therefore your template cannot identify nodes/dijits by IDs as you will have multiple nodes/dijits with the same ID
it's an elegant declarative way, so your code won't be full of dijit.byId/dojo.byId.
It is important to keep track of what is the contents and which is the template of the dijit.Dialog. Once you set contents of a dialog, its markup is parsed - but not in a manner, such that the TemplatedMixin is applied to the content-markup-declared-widgets.
To successfully implement a template, you would need something similar to the following code, note that I've commented where attachPoints kicks in.
This SitePen blog renders nice info on the subject
define(
[
"dojo/declare",
"dojo/_base/lang",
"dijit/_Templated",
"dijit/_Widget",
"dijit/Dialog"
], function(
declare,
lang,
_Templated,
_Widget,
Dialog
) {
return declare("my.Dialog", [Dialog, _Templated], {
// set any widget (Dialog construct) default parameters here
toggle: 'standard',
// render the dijit over a specific template
// you should be aware, that once this templateString is overloaded,
// then the one within Dialog is not rendered
templateString: '<div bgColor="#FFFFFF" bgOpacity="0.4">' +// our domNode reference
'<div class="dijitInline">' +
// setting a dojoAttachPoint makes it referencable from within widget by this attribute's value
' <input type="input" class="dateWidgetInput" dojoAttachPoint="numberOfDateNode" selected="true">' +
'</div>' +
'</div>',
constructor: function(args, srcNodeRef) {
args = args || {} // assert, we must mixin minimum an empty object
lang.mixin(this, args);
},
postCreate: function() {
// with most overrides, preferred way is to call super functionality first
this.inherited(arguments);
// here we can manipulate the contents of our widget,
// template parser _has run from this point forward
var input = this.numberOfDateNode;
// say we want to perform something on the numberOfDateNode, do so
},
// say we want to use dojo.Stateful pattern such that a call like
// myDialogInstance.set("dateValue", 1234)
// will automatically set the input.value, do as follows
_setDateValueAttr: function(val) {
// NB: USING dojoAttachPoint REFERENCE
this.numberOfDateNode.value = val;
},
// and in turn we must set up the getter
_getDateValueAttr: function() {
// NB: USING dojoAttachPoint REFERENCE
return this.numberOfDateNode.value;
}
});
});