Coder Social home page Coder Social logo

Parser example to avoid using the parent scope if a value is null on the main scope : onlyDeepestScope bug about docxtemplater HOT 11 CLOSED

nestorps avatar nestorps commented on September 26, 2024
Parser example to avoid using the parent scope if a value is null on the main scope : onlyDeepestScope bug

from docxtemplater.

Comments (11)

edi9999 avatar edi9999 commented on September 26, 2024

First possibility

If you want to set the scope to never traverse, then you can use

 parser: (tag: any) => {
      return {
       get(scope, context) {
            if (context.num < context.scopePath.length) {
                return null;
            }
            // You can customize your parser here instead of scope[tag] of course
            return scope[tag];
        },
      };
    },

In that case you can remove the "!" prefix.

Second possibility

If you use following code, it will traverse except if the tag starts with "!"

const docTmp = new docxtemplater().loadZip(zippedTemplate).setOptions({
    parser: (tag: any) => {
      return {
        get(scope: any, context: any) {
          const onlyDeepestScope = tag[0] === '!';
          if (onlyDeepestScope) {
            if (context.num < context.scopePath.length) {
              return null;
            } else {
              // Remove the leading "!", ie: "!name" => "name"
              tag = tag.substr(1);
            }
          }
          // You can customize the rest of your parser here instead of
          // scope[tag], by using the angular-parser for example.
          return scope[tag];
        },
      };
    },
    nullGetter: (tag: any, props: any) => {
      return '';
    },
    linebreaks: true,
    paragraphLoop: true,
  });

In that case, your template should be like this if you don't want to let the scope traverse on the portraitMedia

{#entities}Títol de l’exposició: {#activity}{title}
Lloc de l’exposició: {place}
Dates de l’exposició: {dateSince} - {dateUntil}{/activity}
 
{#objects}{#object}{display}
{materialsTechsDisplay}
{measurementsDisplay}
{currentLocation.label}
{creditLine}
Valor assegurança actual: {#valuationAmount}{valuationAmount} EUR {/valuationAmount}	 
{#!portraitMedia}**{!original}**{/!portraitMedia}
{/object}{/objects}
{/entities}

from docxtemplater.

nestorps avatar nestorps commented on September 26, 2024

Thanks for the quick response. Try to add the ! to portraitMedia with the second posibility with no luck:

{#!portraitMedia}{!original}{/!portraitMedia}

still showing the portraitMedia.original from entities

any ideas, thanks in advance

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Can you send the data that you're using ?

By the way, I recommend to use the v4 api, that is :

new docxtemplater(zippedTemplate, {
    parser: (tag: any) => {
      return {
        get(scope: any, context: any) {
          const onlyDeepestScope = tag[0] === '!';
          if (onlyDeepestScope) {
            if (context.num < context.scopePath.length) {
              return null;
            } else {
              // Remove the leading "!", ie: "!name" => "name"
              tag = tag.substr(1);
            }
          }
          // You can customize the rest of your parser here instead of
          // scope[tag], by using the angular-parser for example.
          return scope[tag];
        },
      };
    },
    nullGetter: (tag: any, props: any) => {
      return '';
    },
    linebreaks: true,
    paragraphLoop: true,
  });

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Here is a diff of some test files where I have made the test work

diff --git a/es6/tests/e2e/fixtures.js b/es6/tests/e2e/fixtures.js
index 0582cf30..bea56494 100644
--- a/es6/tests/e2e/fixtures.js
+++ b/es6/tests/e2e/fixtures.js
@@ -132,6 +132,99 @@ const fixtures = [
 			endText,
 		],
 	},
+	{
+		content: `<w:t>
+		{#entities}
+			Títol de l’exposició:
+			{#activity}
+			{title} Lloc de l’exposició: {place}
+			Dates de l’exposició: {dateSince} - {dateUntil}
+			{/activity}
+
+			{#objects}
+			{#object}
+			{display}
+			{materialsTechsDisplay}
+			{measurementsDisplay}
+			{currentLocation.label}
+			{creditLine}
+			Valor assegurança actual: {#valuationAmount}{valuationAmount} EUR {/valuationAmount}
+			{#!portraitMedia}**{!original}**{/!portraitMedia}
+			{/object}{/objects}
+		{/entities}
+		</w:t>`,
+		options: {
+			parser: (tag) => {
+				return {
+					get(scope, context) {
+						const onlyDeepestScope = tag[0] === "!";
+						if (onlyDeepestScope) {
+							if (context.num < context.scopePath.length) {
+								return null;
+							} else {
+								// Remove the leading "!", ie: "!name" => "name"
+								tag = tag.substr(1);
+							}
+						}
+						// You can customize the rest of your parser here instead of
+						// scope[tag], by using the angular-parser for example.
+						return scope[tag];
+					},
+				};
+			},
+			nullGetter: (tag, props) => {
+				return "";
+			},
+			linebreaks: true,
+			paragraphLoop: true,
+		},
+		scope: {
+			entities: [
+				{
+					activity: true,
+					title: "John",
+					place: "New York",
+					dateSince: "2023-06-11",
+					dateUntil: "2023-08-11",
+					objects: [
+						{
+							object: {
+								display: "hi",
+								portraitMedia: [
+									{
+										original: "YES",
+									},
+								],
+							},
+						},
+					],
+				},
+			],
+		},
+		result: '<w:t xml:space="preserve">Hi Foo</w:t>',
+		postparsed: [
+			xmlSpacePreserveTag,
+			content("Hi "),
+			{ type: "placeholder", value: "." },
+			endText,
+		],
+		only: true,
+		it: "should do #721",
+		lexed: [
+			startText,
+			content("Hi "),
+			delimiters.start,
+			content("."),
+			delimiters.end,
+			endText,
+		],
+		parsed: [
+			startText,
+			content("Hi "),
+			{ type: "placeholder", value: "." },
+			endText,
+		],
+	},
 	{
 		it: "should handle {.} with tag",
 		content: "<w:t>Hi {.}</w:t>",

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Hello @nestorps ,

Your JSON is too complex, I can't tell easily what the expected output should be and what you currently have as the output.

Please simplify your template and data to come up with an issue that is reproducible and simple enough to understand.

from docxtemplater.

nestorps avatar nestorps commented on September 26, 2024

Hi, I tried to reduce json to the significant fields:

{
  entities: [
    {
      mainTask: {
        referenceNumber: "T-000030",
        label: "[T-000030 / Moviment]",
        
      },
      activity: {
        event: {
          label: "Europa i l'art, 1-3-2019 - 5-8-2019"
        },
        title: "Europa i l'art",
      },
      objects: [
        {
          display: "prova 0001234142 - cable / 0 €",
          object: {
            objectNumber: "aa.0123834",
            portraitMedia: {
              original: "https://coeli-staging-eu-macba-test.s3-eu-west-1.amazonaws.com/private/DigitalAsset/0bcce599-a496-48ec-b829-80e3faf421d6/cd460cf6873e2f6b4d8a706df5cfe034/full/original/0/default.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230613T134252Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAINEAG7AQJT6DQBMQ%2F20230613%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=712b4b98fa8939192458ff7bcc2cb9118aeb4b8e9ed68fcf6f2bbfb44d8c8bdc",
              
            },
            
          },
          
        },
        {
          display: "CF2953.001 - Wind [videocasset], Joan Jonas, 1968",
          object: {
            objectNumber: "CF2953.001",
            portraitMedia: {
              original: "https://coeli-staging-eu-macba-test.s3-eu-west-1.amazonaws.com/uploads/DigitalAsset/7603f97bfd2ebd7eb13eb0fad48fe3fe.jpg",
              
            },
            
          },
          
        },
        {
          display: "A0001.0004 - sobre, 2023 a",
          object: {
            objectNumber: "A0001.0004",
            
          },
          
        },
        {
          display: "A.JBR.00002 / 5 €",
          object: {
            objectNumber: "A.JBR.00002",
            
          },
          
        }
      ],
      portraitMedia: {
        original: "https://coeli-staging-eu-macba-test.s3-eu-west-1.amazonaws.com/private/DigitalAsset/0bcce599-a496-48ec-b829-80e3faf421d6/cd460cf6873e2f6b4d8a706df5cfe034/full/original/0/default.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230613T134252Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAINEAG7AQJT6DQBMQ%2F20230613%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Signature=712b4b98fa8939192458ff7bcc2cb9118aeb4b8e9ed68fcf6f2bbfb44d8c8bdc",
        
      }
    }
  ]
}

{#entities}Títol de l’exposició: {#activity}{title}{/activity}
{#objects}
{#object}
{display}
{#!portraitMedia}{!original}{/!portraitMedia}
{/object}
{/objects}
{/entities}

The expected output is 4 rows with objects info. Only the two first rows has portraitMedia.original but the output is showing the portraitMedia.original from root scope on the other two rows as well.

thanks for your time

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Thanks for the reproduction, it is indeed a bug.

The parser was incorrect, it had a bug indeed !!

The parser should instead be :

			parser: (tag) => {
				const onlyDeepestScope = tag[0] === "!";
				if (onlyDeepestScope) {
					// Remove the leading "!", ie: "!name" => "name"
					tag = tag.substr(1);
				}
				return {
					get(scope, context) {
						if (onlyDeepestScope && context.num < context.scopePath.length) {
							return null;
						}
						return scope[tag];
					},
				};
			},

The difference is subtle, because the get() function was called multiple times. And since the tag was changed after the first get(). it would work only for the first item in the array, and after that, it would totally ignore the ! prefix.

Thanks for the issue, I will also be updating the documentation.

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Online doc is now updated

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

I would be very grateful if you can endorse docxtemplater here (preferably by video) : https://testimonial.to/docxtemplater

This will increase the trust my users have in the library and project.

from docxtemplater.

nestorps avatar nestorps commented on September 26, 2024

Hi, thanks for your help. It's working now.
The code is this thread is different from the documentation. There's an extra return. I dont know if it's correct as well.

from docxtemplater.

edi9999 avatar edi9999 commented on September 26, 2024

Thanks, the code from the doc indeed had syntax errors.

Thanks for pointing that out.

from docxtemplater.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.