I'm building a html email with groovy and I want to style my elements using a method. I want to use the method createTableCSS to set style to my table. But it doesn't work. The styling is coming outside the table tag.
String createTableCSS(String width, String border, String cellSpacing, String background, String classes ){
return "'width':'"+width+"'"
}
def responseDoc = job.addDocument("ECommerce_test.html"){out ->
def xmlWriter = new OutputStreamWriter(out)
MarkupBuilder html = new MarkupBuilder(xmlWriter)
html.doubleQuotes = true
html.expandEmptyElements = true
html.omitEmptyAttributes = false
html.omitNullAttributes = false
html.escapeAttributes = false
html.html(lang:'en') {
head {
title('E-Commerce email')
base('target':'_blank')
meta('http-equiv' : 'Content-Type', 'content' : 'text/html; charset=ISO-8859-1')
meta('name':'viewport', 'content':'width=320')
style(type:"text/css", '''
''')
}
body('style':'padding:0; margin:0; -webkit-text-size-adjust:none; width:100%;','bgcolor':'#F2F2F2') {
div(){
table(){ //Container table
tr(){
td('width':'20','class':'nomob'){
}
td('align':'center'){
table(createTableCSS("640", "", "", "", "")){
}
}
td(){
}
}
}
}
} //End <body>
} //End <html>
}
The result looks like this
<table>'width':'640'</table>
and it should look like this
<table width:"640"></table>
I can do this without a method, but would really like to know how to use a method in this type of code.
The problem in here is, that using this method results in a string given as parameter into the table closure. What you need to make this work is a method returning a map. You can solve this by replacing your method with this one:
def createTableCSS(String width, String border, String cellSpacing, String background, String classes) {
return [width: width]
}
Related
How can i handle the following code
List books = ['book1', book2]
String getTextWidget() {
return // here i need to only return the element which is 'book1' such as if books.contains('book1') return this element as String ;
}
the i need to put it in Text Widget like so
Container(
child Text(getTextWidget())
)
i tried the following code , it is work but it does not accept String Widget
getTextWidget() {
books .forEach((element) {
if(element.contains('book1')){
'book1'
}
});
}
I think you'd benefit from the .firstWhere method on your list.
void main() {
// an arbitrary object that is not type String
final book2 = Object();
List books = ['book1', book2];
print(getTextElement(books)); // book1
}
String? getTextElement(List list) {
return list.firstWhere((e) => e is String);
}
try this , give "book1" to the methode as a parameter
String getTextWidget(String nameofbook) {
if(books.contains(nameofbook)==true){
return nameofbook;
}
else return null;
}
In python, I often use strings as templates, e.g.
templateUrl = '{host}/api/v3/{container}/{resourceid}'
params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
api.get(templateUrl.format(**params))
This allows for easy base class setup and the like. How can I do the same in dart?
I'm assuming I will need to create a utility function to parse the template and substitute manually but really hoping there is something ready to use.
Perhaps a TemplateString class with a format method that takes a Map of name/value pairs to substitute into the string.
Note: the objective is to have a generic "format" or "interpolation" function that doesn't need to know in advance what tags or names will exist in the template.
Further clarification: the templates themselves are not resolved when they are set up. Specifically, the template is defined in one place in the code and then used in many other places.
Dart does not have a generic template string functionality that would allow you to insert values into your template at runtime.
Dart only allows you to interpolate strings with variables using the $ syntax in strings, e.g. var string = '$domain/api/v3/${actions.get}'. You would need to have all the variables defined in your code beforehand.
However, you can easily create your own implementation.
Implementation
You pretty much explained how to do it in your question yourself: you pass a map and use it to have generic access to the parameters using the [] operator.
To convert the template string into something that is easy to access, I would simply create another List containing fixed components, like /api/v3/ and another Map that holds generic components with their name and their position in the template string.
class TemplateString {
final List<String> fixedComponents;
final Map<int, String> genericComponents;
int totalComponents;
TemplateString(String template)
: fixedComponents = <String>[],
genericComponents = <int, String>{},
totalComponents = 0 {
final List<String> components = template.split('{');
for (String component in components) {
if (component == '') continue; // If the template starts with "{", skip the first element.
final split = component.split('}');
if (split.length != 1) {
// The condition allows for template strings without parameters.
genericComponents[totalComponents] = split.first;
totalComponents++;
}
if (split.last != '') {
fixedComponents.add(split.last);
totalComponents++;
}
}
}
String format(Map<String, dynamic> params) {
String result = '';
int fixedComponent = 0;
for (int i = 0; i < totalComponents; i++) {
if (genericComponents.containsKey(i)) {
result += '${params[genericComponents[i]]}';
continue;
}
result += fixedComponents[fixedComponent++];
}
return result;
}
}
Here would be an example usage, I hope that the result is what you expected:
main() {
final templateUrl = TemplateString('{host}/api/v3/{container}/{resourceid}');
final params = <String, dynamic>{'host': 'www.api.com', 'container': 'books', 'resourceid': 10};
print(templateUrl.format(params)); // www.api.com/api/v3/books/10
}
Here it is as a Gist.
Here is my solution:
extension StringFormating on String {
String format(List<String> values) {
int index = 0;
return replaceAllMapped(new RegExp(r'{.*?}'), (_) {
final value = values[index];
index++;
return value;
});
}
String formatWithMap(Map<String, String> mappedValues) {
return replaceAllMapped(new RegExp(r'{(.*?)}'), (match) {
final mapped = mappedValues[match[1]];
if (mapped == null)
throw ArgumentError(
'$mappedValues does not contain the key "${match[1]}"');
return mapped;
});
}
}
This gives you a very similar functionality to what python offers:
"Test {} with {}!".format(["it", "foo"]);
"Test {a} with {b}!".formatWithMap({"a": "it", "b": "foo"})
both return "Test it with foo!"
It's even more easy in Dart. Sample code below :
String host = "www.api.com"
String container = "books"
int resourceId = 10
String templateUrl = "$host/api/v3/$container/${resourceId.toString()}"
With the map, you can do as follows :
Map<String, String> params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
String templateUrl = "${params['host']}/api/v3/${params['container']}/${params['resourceId']}"
Note : The above code defines Map as <String, String>. You might want <String, Dynamic> (and use .toString())
Wouldn't it be simplest to just make it a function with named arguments? You could add some input validation if you wanted to.
String templateUrl({String host = "", String container = "", int resourceid = 0 }) {
return "$host/api/v3/$container/$resourceId";
}
void main() {
api.get(templateUrl(host:"www.api.com", container:"books", resourceid:10));
}
I would like to have an image in column for boolean type. To specify column properties, I use OLVColumn attribute and there I specify ImageAspectName.
[OLVColumn("UseK", DisplayIndex = 4, ImageAspectName = "ImageForUseK", CheckBoxes = false, Width = 40)]
public bool UseK
{
get { return useK; }
set
{
if (useK == value) return;
useK = value;
OnPropertyChanged("UseK");
}
}
protected bool useK = true;
public string ImageForUseK()
{
return "success";
}
This works fine and displaying image in column, but also displaying literal "True" next to image.
How can I avoid displaying string value of boolean property, while still using ImageAspectName?
You could set AspectToStringFormat to a space.
I have a simple Groovy method that uses Groovy's MarkupBuilder to print HTML, very simplified version below:
void writeHtmlFile(<args>) {
def writer = new FileWriter(fileName.toFile())
def html = new MarkupBuilder(writer)
html.mkp.yieldUnescaped '<!DOCTYPE html>'
html.mkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
html.html {
head { ... }
body(id: 'main') {
h1 "Report Title"
}
}
writer.flush()
writer.close()
}
This works well. Say I wanted to call a method after the h1 that does some calculations and adds more to the MarkupBuilder. How do I get the elements defined in the called method added to the MarkupBuilder? Here's something I tried that doesn't cause an exception, but also doesn't work (the resulting HTML has no <h2> element):
Closure testNested() {
println '---'
return { h2 "here's a subheading" }
}
// .... other stuff from above example not repeated ...
html.html {
head {...}
body(id: 'main') {
h1 "Report Title"
testNested()
}
I know I can easily do this inline. I'm trying to deepen my understanding of how Groovy uses closures and delegates in DSLs and clearly I'm missing something.
Consider the following code, which executes fine for me, using Groovy 2.4.5.
The builder pattern is a bit tricky because it can be viewed as hierarchical data and/or code, depending on your perspective. With practice, one can switch perspectives as necessary.
import groovy.xml.*
void testNested(def html) {
html.h2("here's a subheading from testNested")
}
void writeHtmlFile(def fileName) {
def writer = new FileWriter(fileName)
def html = new MarkupBuilder(writer)
html.mkp.yieldUnescaped '<!DOCTYPE html>'
html.mkp.xmlDeclaration(version: "1.0", encoding: "utf-8")
html.html {
body(id: 'main') {
h1 "Report Title"
testNested(html)
}
}
writer.flush()
writer.close()
}
writeHtmlFile("out.html")
Imagine I have this structure:
class Foo {
String bar
}
Now imagine I have several instance of Foo whose bar value is baz_1, baz_2, and zab_3.
I want to write a collect statement that only collects the bar values which contain the text baz. I cannot get it to work, but it would look something like this:
def barsOfAllFoos = Foo.getAll().bar
assert barsOfAllFoos == [ 'baz_1', 'baz_2', 'zab_3' ]
def barsWithBaz = barsOfAllFoos.collect{ if( it.contains( "baz" ) { it } ) } // What is the correct syntax for this?
assert barsWithBaz == [ 'baz_1', 'baz_2' ]
You need findAll:
barsOfAllFoos.findAll { it.contains 'baz' }
If you want to both filter and transform there's lots of ways to do this. After 1.8.1 I'd go with #findResults and a closure that returns null for the elements I want to skip.
def frob(final it) { "frobbed $it" }
final barsWithBaz = barsOfAllFoos.findResults {
it.contains('baz')? frob(it) : null
}
In earlier versions you can use #findAll and #collect
final barsWithBaz = barsOfAllFoos
. findAll { it.contains('baz') }
. collect { frob(it) }
Or #sum
final barsWithBaz = barsOfAllFoos.sum([]) {
it.contains('baz')? [frob(it)] : []
}
Or #inject
final barsWithBaz = barsOfAllFoos.inject([]) {
l, it -> it.contains('baz')? l << frob(it) : l
}
Using findResults did not work for me... If you want to collect a transformed version of the values matching the condition (for instance a regex search of many lines) you can use collect followed by find or findAll as follows.
def html = """
<p>this is some example data</p>
<script type='text/javascript'>
form.action = 'http://www.example.com/'
// ...
</script>
"""
println("Getting url from html...")
// Extract the url needed to upload the form
def url = html.split("\n").collect{line->
def m = line =~/.*form\.action = '(.+)'.*/
if (m.matches()) {
println "Match found!"
return m[0][1]
}
}.find()
println "url = '${url}'"
This returns the part of the line matching the given pattern.
Getting url from html...
Match found!
url = 'http://www.example.com/'