How to assign values to nested object in freemarker - html-email

This could be simple but i couldn't find it on internet.
I have nested object in freemarker as below which has multiple key i am not able to assign value to more than one key I am able to assign value to only one key
<#assign modifiedObjectChng = {
"beforeDep": {
"range": [],
"newTravelDate": "",
"reissueAllowed": false,
"changeAllowed": false,
"maxPenality": ""
},
"afterDep": {
"range": [],
"newTravelDate": "",
"reissueAllowed": false,
"changeAllowed": false,
"maxPenality": ""
}
}>
<#assign modifiedObjectChng = modifiedObjectChng + { "beforeDep" : {"newTravelDate" : "AAA" }}>
<#assign modifiedObjectChng = modifiedObjectChng + { "beforeDep" : {"reissueAllowed" : "BBB" }}>
${modifiedObjectChng.beforeDep.newTravelDate} //Output : error following has evaluated to null
${modifiedObjectChng.beforeDep.reissueAllowed} // gives correct result
My problem is how will i assign value to multiple keys i am able to do with only one key
Thanks in advance

You can do it like this:
<#assign modifiedObjectChng = modifiedObjectChng + { "beforeDep" : modifiedObjectChng.beforeDep + {"newTravelDate" : "AAA" }}>
<#assign modifiedObjectChng = modifiedObjectChng + { "beforeDep" : modifiedObjectChng.beforeDep + {"reissueAllowed" : "BBB" }}>
Not very nice, but FreeMarker doesn't support modifying the objects that was passed to the template. It's more convenient if the setter methods are exposed (see ?api), but in general it's quite odd if templates modify objects.

Related

Angular PrimeNg Using autocomplete and passing REST object

I have an issue with PrimeNg autocomplete :
When i type any research, I obtain [Object Object] in the input text.
First I have an API call for getting a data set :
ngOnInit(): void {
this.getCategories();
}
private getCategories(): void {
const response = this.apiService.getCategories().subscribe(
(data) => {
this.categories = data as CategoriesModel[];
}
);
console.log('Get categories');
console.log('response ', response);
}
It allows me to retrive my data correctly (here is a sample) :
[
{
"id": "1",
"categoryName": "Name1",
"docDescription": "Description1 ..."
},
{
"id": "2",
"categoryName": "Name2",
"docDescription": "Description2"
}..
]
Now I try to handle my array of javascript objects in order to filter them :
I defined member variables in my component :
categories: CategoriesModel[];
filteredCategories: CategoriesModel[];
category: CategoriesModel;
I add this code into the HTML template:
<p-autoComplete
[(ngModel)]="category"
[suggestions]="filteredCategories"
(completeMethod)="filterCategories($event)"
[size]="30"
[minLength]="1" placeholder="Hint: type a letter"
[dropdown]="true">
<ng-template let-category pTemplate="item.categoryName">
<div class="ui-helper-clearfix" style="border-bottom:1px solid #D5D5D5">
{{category.id}}
<div style="font-size:18px;float:right;margin:10px 10px 0 0">{{category.categoryName}}</div>
</div>
</ng-template>
</p-autoComplete>
<span style="margin-left:50px">Category: {{category?.categoryName||'none'}}</span>
Now I try to use a filter method that will show in list results :
filterCategories(event): void {
this.filteredCategories = [];
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < this.categories.length; i++) {
this.category = this.categories[i];
if (this.category.categoryName.toLowerCase().indexOf(event.query.toLowerCase()) === 0) {
console.log(this.category.categoryName);
this.filteredCategories.push(this.category);
}
}
}
I finally solved this by modifying the template :
<p-autoComplete
[(ngModel)]="category"
[suggestions]="filteredCategories"
field = "categoryName"
(completeMethod)="filterCategories($event)"
[size]="30"
[minLength]="1" placeholder="Hint: type a letter"
[dropdown]="true">
<ng-template let-category pTemplate="categoryName">
<div class="ui-helper-clearfix" style="border-bottom:1px solid #D5D5D5">
{{category.id}} {{category.categoryName}}
</div>
</ng-template>
</p-autoComplete>

Return a value with highlighted color

Requirement: I have a fragment.xml file which I am extending. The form element is currently being processed with a formatter.js where I am validating some values based on some condition:
In Fragment, the formatter function is getting called correctly
<Text text="{
parts: [
{path: 'ZName1'},
{path: 'ZStatus1'}
],
formatter: '.Formatter.delivery'
}" >
Formatter:
delivery: function(iName, iStatus) {
var sResult = "";
if(iStatus === "A" ) {
sResult = iName ;
} else if(iStatus === "P") {
sResult = iName ;
} else {
sResult = iName ;
}
return sResult ;
}
In the output, I should get sResult highlighted either in green, yellow, or red based on the condition.
Binding on text will not work for highlighting the text. refer the example for alternative solution.
<Text id="id" text="{ZName1}" class="{parts: [{path: 'ZName1'},{path: 'ZStatus1'} ],
formatter : '.Formatter.delivery'}">
In Format.js file:
delivery: function(iName, iStatus) {
var idText = this.byId("id");
if(iStatus === "A" ) {
idText.removeStyleClass("classForYellowColor");
idText.removeStyleClass("classForRedColor");
return "classForGreenColor";
} else if(iStatus === "P") {
idText.removeStyleClass("classForGreenColor");
idText.removeStyleClass("classForRedColor");
return "classForYellowColor";
} else {
idText.removeStyleClass("classForGreenColor");
idText.removeStyleClass("classForYellowColor");
return "classForRedColor";
}
}
Instead of plain sap.m.Text, take advantage of sap.m.ObjectStatus which works exactly like Text but supports semantic colors (via state) out-of-the-box.
Run the following snippet to see the results:
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/m/List",
"sap/m/CustomListItem",
"sap/m/ObjectStatus", // instead of Text
"sap/ui/core/ValueState",
"sap/ui/model/json/JSONModel",
], (List, Item, ObjectStatus, ValueState, JSONModel) => new List().bindItems({
path: "/myData",
template: new Item().addContent(new ObjectStatus({
text: "{ZName1}",
state: {
path: "ZStatus1",
formatter: status =>
status === "A" ? ValueState.Success : // Green
status === "P" ? ValueState.Warning : // Yellow
status === "Z" ? ValueState.Error : // Red
ValueState.None
},
}).addStyleClass("sapUiSmallMargin")),
}).setModel(new JSONModel({
myData: [
{
ZName1: "Success",
ZStatus1: "A"
},
{
ZName1: "Warning",
ZStatus1: "P"
},
{
ZName1: "Error",
ZStatus1: "Z"
},
{
ZName1: "None",
ZStatus1: ""
},
],
})).placeAt("content")));
<script>
window["sap-ui-config"] = {
libs: "sap.ui.core, sap.m",
preload: "async",
theme: "sap_belize",
compatVersion: "edge",
"xx-waitForTheme": true,
"xx-async": true
}
</script>
<script id="sap-ui-bootstrap" src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
We can see green, yellow, and red depending on the condition.
In Fragment file:
<Text text="{parts: [{path: 'ZName1'},{path: 'ZStatus1'}],
formatter : '.Formatter.delivery'}" >
In CSS file:
.greenTxtHlight {
color: green;
}
.yellowTxtHlight {
color: yellow;
}
.redTxtHlight {
color: red;
}
In Formatter file:
delivery: function(sName, sStatus) {
switch(sStatus){
case "A":
this.addStyleClass("greenTxtHlight");
this.removeStyleClass("yellowTxtHlight");
this.removeStyleClass("redTxtHlight");
break;
case "P":
this.removeStyleClass("greenTxtHlight");
this.addStyleClass("yellowTxtHlight");
this.removeStyleClass("redTxtHlight");
break;
case "G"://Update this
this.removeStyleClass("greenTxtHlight");
this.removeStyleClass("yellowTxtHlight");
this.addStyleClass("redTxtHlight");
break;
}
return sName;
}

Meteor Reactive Tables nested data

I have reactive tables working with meteor. I am trying to implement a simple master detail solution. Basically When a row is selected in table 1 the details come up in table 2. When I try and access nested data it shows up in my table as [object: Object]
I am using this package: https://github.com/aslagle/reactive-table#nested-objects-and-arrays
my schema looks like:
ActivityLogs = new Meteor.Collection ('activityLogs');
ActivityLogsSchema = new SimpleSchema({
"aid" : {
type: String,
label: "aid"
},
"logs": {
type: Array
},
"logs.$": {
type: Object
},
"logs.$.stdout": {
type: String
}
});
ActivityLogs.attachSchema( ActivityLogsSchema );
ActivityLogs.attachSchema( ActivityLogsSchema );
in my html:
{{> reactiveTable collection=activityStdout settings=settings1}}
My activityStdout helper:
activityStdout: function() {
var aid = Session.get('selectedAid');
if (aid != null) {
// return ActivityLogs.find({"aid": aid}, {"logs.stdout": 1});
return ActivityLogs.find({"aid": aid});
}
The collection data looks like:
db.activityLogs.find({aid:"7aba0960-b31f-11e7-af97-c56765123d72"}).pretty();
{
"_id" : ObjectId("59e5d080702ec0000df939b6"),
"aid" : "7aba0960-b31f-11e7-af97-c56765123d72",
"logs" : [
{
"stdout" : "performed substitutions on asset dir config-dir/app/config-dir/config-dir-file-2.json"
},
{
"stdout" : "performed substitutions on asset dir config-dir/app/config-dir/config-dir-file-1.json"
},
{
"stdout" : "performed substitutions on asset file undefined"
},
{
"stdout" : "created package package::/sandboxeter./pipe5/app/dev2::pipe5-app-config-Sprint-5.7.4"
}
]
}
in my settinggs1 helper:
settings1: function () {
return {
// collection: activityStdout,
rowsPerPage: 25,
showNavigation: 'auto',
showFilter: false,
fields: [
// {key: 'aid' , label: 'AID' },
{key: 'logs' , label: 'Logs'},
{key: 'stdout' , label: 'output'}
]
};
}
I would like my reactive table to show any key in the logs array. I have been playing with the key above. I have tried: logs.stdout, logs.$.stdout and several other variants with the key.
In the table I get:
The below code works to get the right data but it doent use the reactive table:
<table id="mytable2" class="table table-striped table-bordered table-hover">
<tr>
<td>{{aid}}</td>
</tr>
{{#each activitiesLogList}}
{{#each logs}}
<tr> {{stdout}} </tr>
{{/each}}
{{/each}}
</table>
Any thoughts are appreciated.
After much time with google this is apparently isnt supported with this Meteor Package.
I found this: https://github.com/aslagle/reactive-table/issues/376
The Author Package says:
The only thing that works right now is a specific array index, like
notes.0.remindersActive. There's no way to filter for something
anywhere in the array. Do those work in mongo selectors?

Is this possible to set the language in tinymce editor in javascript?

I have using tinymce text edit for my asp.net applications.Now i have added language pack.now i want to set the language pack for the text editor programatically.And also hide the language pack bar from the visible state.
for example : i want to programatically set the language of the text editior is hindi.Pleasr guide me to get out of this...
whenever user clicks translation Button in my web form , i have initialized this string variable.then i want to set the tinymce editor language programatically.
string lang="Hindi";
ptp.js
function LoadTypePad()
{
// Initialize pad
tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
skin : "o2k7",
skin_variant : "silver",
plugins : "safari,style,table,advhr,advimage,advlink,inlinepopups,insertdatetime,preview,media,searchreplace,print,paste,fullscreen,indicime,aksharspellchecker",
// Theme options
theme_advanced_buttons1 : "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,formatselect,fontsizeselect,fontselect,aksharspellchecker,indicime, indicimehelp",
theme_advanced_buttons2 : "selectall,cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,media,advhr,|,print",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
spellchecker_rpc_url:"http://service.vishalon.net/spellchecker.aspx",
// Example content CSS (should be your site CSS)
content_css : "css/content.css",
// Drop lists for link/image/media/template dialogs
template_external_list_url : "lists/template_list.js",
external_link_list_url : "lists/link_list.js",
external_image_list_url : "lists/image_list.js",
media_external_list_url : "lists/media_list.js",
width : "100%",
init_instance_callback : "afterInit"
});
}
function showPleaseWait()
{
var mainMessage = document.getElementById("message").innerHTML;
document.getElementById("message").innerHTML = pleaseWait;
pleaseWait = mainMessage;
}
// This function finds absolute position of the element in screen and returns array.
function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return [curleft,curtop];
}
}
// id= outer most id for show/hide. baseid = reference id for pointer
function showPopup(id, baseid)
{
toggle_menu(id);
var base = document.getElementById(baseid);
var l = findPos(base);
var obj = document.getElementById(id + 'content');
var im = document.getElementById(id + 'img');
var left = im.src.indexOf('left.gif') > 0;
obj.style.top = (l[1] - obj.offsetHeight - 20) + "px";
obj.style.left = (l[0] + (base.offsetWidth/2) - (left?obj.offsetWidth:0)) + "px";
l = findPos(obj);
im.style.top = (l[1] + obj.offsetHeight - 1) + "px";
im.style.left = (l[0] + (left?obj.offsetWidth - 26:0)) + "px";
}
function closePopup()
{
// hide popup
var elem = document.getElementById("step1");
elem.style.display = "none";
elem = document.getElementById("step2");
elem.style.display = "none";
elem = document.getElementById("step3");
elem.style.display = "none";
}
// Once tinymce is fully loaded
function afterInit()
{
// Find search string from referral
var term = document.referrer;
var re = /bengali|gujarati|gujrati|hindi|marathi|devnagari|devanagari|punjabi|gurmukhi|kannada|malayalam|tamil|telugu|thelugu|thamil/gi ;
var m = re.exec(term);
var result ='';
if (m != null && m.length > 0)
result = "<strong>" + m[0] + "</strong>";
else
result = "your favourite Indic Script";
// Create popup
CreatePopup("step1", "Step 1", "Click here to erase existing contents", "right");
CreatePopup("step2", "Step 2", "Select " + result + " from this dropdown list and start typing.", "left");
CreatePopup("step3", "Step 3", "Click here to get a help for typing once you selected script in Step 2", "right");
// Restore the message from please wait to spell checker
document.getElementById("message").innerHTML = "Now Akshar Spell Checker for Gujarati is available!!! Click on <img src=\"tiny_mce/plugins/aksharspellchecker/img/aksharspellchecker.gif\"> to check Gujarati spelling";
// Initialize for google search
pph = new PramukhPhoneticHandler();
pph.convertToIndicIME("q");
pph.onScriptChange("q", indicChange);
// Open up popups
showPopup("step1","elm1_newdocument");
showPopup("step2","elm1_indicime");
showPopup("step3","elm1_indicimehelp");
// Close popup after xx seconds.
setTimeout("closePopup();",15000);
}
function toggle_menu(id)
{
var elem = document.getElementById(id);
elem.style.display = elem.style.display=="none"? "":"none";
}
function CheckNewVersion()
{
var JSONRequest = tinymce.util.JSONRequest;
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
} catch (e) {
// do nothing
}
JSONRequest.sendRPC({
url : "http://service.vishalon.net/pramukhtypepadmessage.aspx?v=2.5.00",
method : "",
params : "",
type: "GET",
success : function(r){
var message = r.substring(r.indexOf(",")+1);
if (message != "")
document.getElementById("message").innerHTML = "<img src='img/info.jpg' >" + message + "<br><br>";
},
error : function(e, x) {
// do nothing
}
});
}
function indicChange(id, lang)
{
var s = document.getElementById('language');
s.value = lang;
if (lang == null || lang == "")
lang = 'english';
pph.setScript(id, lang);
}
function CreatePopup(id, title,content, dir)
{
var holder = document.getElementById("plholder");
holder.innerHTML += "<div id='" +id + "' style='display:none;'>"+
"<div class='popupbody' id='" +id + "content'>" +
"<div style='float:right;'><img src='img/close.gif' style='cursor:pointer;cursor:hand;' onclick='toggle_menu(\"" + id + "\");'/></div>"+
"<div><strong>" + title + "</strong></div>"+
"<div style='clear:both'></div>"+
"<div>" + content + "</div>"+
"</div>"+
"<img src='img/" + dir + ".gif' id='" + id + "img' style='position:absolute;'/>"+
"</div>";
}
var pph, pleaseWait = "Please wait while Pramukh Type Pad is loading... <img src='img/progress.gif' /> (Loading problem??? Get Simple Pramukh Type Pad )";
You have to download your language pack and unzip it.
Then you have to put every single js file in the corresponding folder of your tinymce folder.
You have to specify the language as well.
If you're using TinyMCE - jQuery Plugin you have to do something like this:
// Initializes all textareas with the tinymce class
$(document).ready(function() {
$('textarea.tinymce').tinymce({
script_url : '../js/tinymce/jscripts/tiny_mce/tiny_mce.js',
theme : "advanced",
language: "hi",
...
});
});
If you want to remove tinyMCE (and I guess you have to do it if you want to reset the language) from your text-area you can use this code:
tinyMCE.execCommand('mceRemoveControl', false, 'mycontrol_id');
as specified here.
and you can recreate it using the same code.
You can wrap everything in a function and pass the language parameter:
function setup(language) {
tinyMCE.init({
mode : "textareas",
theme : "advanced",
language: language,
plugins : "pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true
});
}
If you want to remove buttons from the toolbar you have to work on these lines:
theme_advanced_buttons1
theme_advanced_buttons2
...
removing those you don't need.
There's a list of all buttons and plugins here.
If you want to add your own buttons you can find a sample here.
UPDATE:
Since you've used your own plugin, I guess you have defined it in the plugin section:
tinyMCE.init({
mode : "textareas",
theme : "advanced",
language: 'hi',
plugins : "myPlugin, pagebreak ... ",
theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "myPlugin",
...
});
If you don't want to show it, just remove it from the theme_advanced_buttons2.

How to select a specific node programmatically?

I have a jstree. I want to select the node which is bound to the object which has a location with id of 158. This works but seems stupid. What's the more idiomatic way of doing this?
var $tree = $('.jstree', myContext),
node = $tree.find('li').filter(function() {
return ( $(this).data().location || {}).id === 158;
});
$tree.jstree('select_node', n)
Just wanted to chime in here as none of the answers worked for me. What finally DID work was very simple:
$('#someTree').jstree('select_node', 'someNodeId');
Note that I didn't initialize someNodeId as a jQuery object. It's just a plain string.
I did this right after a tree was loaded without putting it into a "ready" bind event as it seems to not be necessary.
Hope it saves some one from a few frustrating hours. . .
To hook into the tree after it has been loaded:
.on('loaded.jstree', function() {
// Do something here...
});
Based on jsTree groups you can try
jQuery("#getStartedTree").jstree("select_node", "#test2");
if the data looks like
The JSON in the TextFile.txt - borrowed from your simple example
[
{
"data" : "A node",
"children" : [ "Child 1", "Child 2" ]
},
{
"attr" : { "id" : "test1" },
"data" : {
"title" : "Long format demo",
"attr" : { "id" : "test2", "href" : "#" }
}
}
]
and jsTree set up
My tree container is <div id="getStartedTree">
My jsTree code
$("#getStartedTree").jstree({
"themes": {
"theme": "default",
"url": "../App_Css/Themes/Default/style.css",
"dots": true,
"icons": true
},
"json_data": {
"ajax": {
"url": "../SiteMaps/TextFile.txt",
"dataType": "json",
"data": function(n) {
return { id: n.attr ? n.attr("id") : 0 };
}
}
},
"plugins": ["themes", "json_data", "ui"]
});
Is that what you are after?
I did it with:
$('.jstree').jstree(true).select_node('element id');
this code:
jQuery.each(produto.categorias, function(i, categoria) {
$('#lista-categorias').jstree(true).select_node(categoria.dadoCategoria.id);
});
I was able to simulate a click on a jstree node as an alternative way to select a node.
The following code is what was used :
$(treeIdHandle + " li[id=" + nodeId + "] a").click();
If you're populating the tree using HTML instead of JSON data and wondering how to set the node_id, you just need to set the id attribute of the <li> element!
<div class="tree-menu">
<ul class="menu">
<li id="node_1">
Node 1 - Level 1
<ul class="menu">
<li id="node_3">
Node 3 - Level 2
</li>
</ul>
</li>
<li id="node_2">
Node 2 - Level 1
</li>
</ul>
</div>
Then
$('.tree-menu')
.jstree(true)
.select_node("node_3");
will select the Node 3 - Level 2 node.
For those getting javascript errors, remember to use Full version of jQuery, not the slim version!
For all down voters, here is the demo to prove it's working:
https://jsfiddle.net/davidliang2008/75v3fLbs/7/
i use jstree 3.0.8. don't use 'state'
'plugins' : ['dnd','sort','types','contextmenu','wholerow','ui']
and server offer the json, the selected node has
"state":{"selected":true,"opened":true}
This solution Works for me
// after the tree is loaded
$(".jstree").on("loaded.jstree", function(){
// don't use "#" for ID
$('.jstree').jstree(true).select_node('ElementId');
});
and even in a php loop (dynamically) :
$(".jstree").on("loaded.jstree", function(){
<?php foreach($tree as $node): ?>
$('.jstree').jstree(true).select_node('<?=$node?>');
<?php endforeach;?>
});
Hope this works for you.
i think u should write code to select node after jstree initialized, therefore use this code
$('#jstree')
.on('ready.jstree', function (e, data) {
// do function after jstree initialized
$('#jstree')
.jstree(true)
.select_node('nodeid');
});
hope its work :)
trigger click on first anchor
$("#jstree .jstree-anchor:first").click();
or by node id 158
$("#jstree #158").find(".jstree-anchor:first").click();
$('#' + 158).find(".jstree-anchor:first").click();