HtmlFlow icon indicating copy to clipboard operation
HtmlFlow copied to clipboard

View in inconsistent state when Dynamic block throws an exception!!!

Open 3t-service opened this issue 3 years ago • 5 comments

Looking at https://htmlflow.org/features/ for partial template

static void template(DynamicHtml<Pet> view, Pet pet) { view .form().attrMethod(EnumMethodType.POST) .div().attrClass("form-group has-feedback") .dynamic(div -> view.addPartial(InputField.view, InputField.LV.of("Date", "date", LocalDate.now()))) .__() //div .__() //form``` )

DynamicHtml<T> view does not contain the method form().

The method form() is undefined for the type DynamicHtml<String>

html div and tr exist. I'm using 3.0.2. Is there a work around? I am trying to make a template for head() but this does not exist. The only way to access head is via: html().head()

3t-service avatar Jul 07 '22 10:07 3t-service

You can use 'view.defineRoot()' Also there are other mistakes in the documentation such as taskDetailsTemplate .dynamic needs changing to .of or it will throw exception about nested dynamic

3t-service avatar Jul 07 '22 11:07 3t-service

Thank you @3t-service for your feedback.

Indeed, for that example of partial we cannot directly invoke .form() on view. You are right, one possible workaround is to use defineRoot(). Even so, in this case I prefer to include the form inside a div. I just made that fix on documentation.

Regarding your second alert about wrong use of .dynamic on taskDetailsTemplate I cannot reproduce your observations as it seems to be working fine.

That sample was copied from the following unit test, which I can run without any problem. https://github.com/xmlet/HtmlFlow/blob/master/src/test/java/htmlflow/test/views/HtmlForReadme.java#L104

I am sorry for any annoying about the documentation, I understand your trouble with that. But we are just a few developers maintaining this library and we are always giving priority for new features rather than improving docs.

fmcarvalho avatar Jul 11 '22 15:07 fmcarvalho

I have found a way to replicate You are already in a dynamic block exception.

Here I have defined a dynamic block which adds p tags from a HashMap. There is an intentional error in the first list with a null in item 'c'. After this exception all subsequent calls of view.render fail. How to recover from this?

`HtmlView<HashMap<String, Object>> view1 = DynamicHtml.view(Main::taskDetailsTemplate);

static void taskDetailsTemplate(DynamicHtml<HashMap<String, Object>> view, HashMap<String, Object> task) {
    view
        .html()
            .head()
                .title().text("Task Details").__()
            .__() //head
            .body()
                .dynamic(body -> {
                	for (Map.Entry<String, Object> item : task.entrySet()) {
                        body.p().text(item.getValue()).__();
                    }
                })
            .__() //body
        .__(); // html
}


public static void main(String[] args) {
	HashMap<String, Object> list = new HashMap<String, Object>();
	list.put("a", "item 1");
	list.put("b", "item 2");
	list.put("c", null);

	HashMap<String, Object> list2 = new HashMap<String, Object>();
	list2.put("a", "item 1");
	list2.put("b", "item 2");
	list2.put("c", "item 3");

	try {
		view1.render(list2); // works fine 
	} catch (Exception e) { 
		e.printStackTrace(); 
	}

	try {
		view1.render(list);
	} catch (Exception e) {
		e.printStackTrace(); // null in first list
	}

	try {
		view1.render(list2);
	} catch (Exception e) { 
		e.printStackTrace(); // should not fail, second list is ok
	} 
	// Now all view1.render(object); calls result in You are already in a dynamic block! Do not use dynamic() chained inside another dynamic!

}`

3t-service avatar Jul 18 '22 15:07 3t-service

Great catch @3t-service! There is a bug indeed in dynamic processing that is not dealing with the case where the dynamic block throws an exception leaving the view in inconsistent state.

Regarding your previous comment about:

Also there are other mistakes in the documentation such as taskDetailsTemplate .dynamic needs changing to .of or it will throw exception about nested dynamic

You are right too. The unit test for this documentation had render in comment and I was not running the template. https://github.com/xmlet/HtmlFlow/blob/master/src/test/java/htmlflow/test/views/HtmlForReadme.java#L104

There is a mistake in the template and we have to replace nested dynamic with of. I will fix this in the documentation right now.

Regarding the bug in dynamic I will have to plan a fix, since it requires changes in HtmlApiFaster dependency.

fmcarvalho avatar Jul 20 '22 12:07 fmcarvalho

    HtmlView<HashMap<String, Object>> view1 = DynamicHtml.view(Main::taskDetailsTemplate);

    static void taskDetailsTemplate(DynamicHtml<HashMap<String, Object>> view, HashMap<String, Object> task) {
        try {
          .html()
              .head()
                  .title().text("Task Details").__()
              .__() //head
              .body()
                  .dynamic(body -> {
            	      for (Map.Entry<String, Object> item : task.entrySet()) {
                          body.p().text(item.getValue()).__();
                      }
                  })
              .__() //body
          .__(); // html
        } catch (Exception e) {
            Main.view1 = DynamicHtml.view(Main::taskDetailsTemplate);
            throw e;
        }
  }

I am currently using a workaround where I wrap the view calls in a try statement and recreate the view in case of an exception. It works but I suspect it is not performant. Thanks for looking into this and take care.

3t-service avatar Jul 20 '22 12:07 3t-service