Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table Of Contents - Display a special mark within a page item when a page contains errors #7320

Open
JaneSjs opened this issue Nov 9, 2023 · 7 comments
Assignees
Labels
enhancement user issue An issue or bug reported by users

Comments

@JaneSjs
Copy link
Contributor

JaneSjs commented Nov 9, 2023

User issue: T15426 - enable required panels/pages to ignore custom questions when validating
https://surveyjs.answerdesk.io/internal/ticket/details/T15426


Add an option to display some special mark within a page's title to inform users that a page contains errors.
image

@JaneSjs JaneSjs added enhancement user issue An issue or bug reported by users labels Nov 9, 2023
@JaneSjs
Copy link
Contributor Author

JaneSjs commented Nov 17, 2023

It is possible to display a special sign for a Table Of Contents page item using the Markdown feature.

View CodeSandbox.

Here are main implementation steps.

  • Use the page.navigationTitle to specify the caption which appears within Table Of Contents.
  • Register a custom page property. The property would indicate whether or not a page navigation title contains an error mark. The property will be further used within the survey.onTextMarkdown callback.
import { Serializer } from "survey-core";

Serializer.addProperty("page", {
  name: "errorMarkExists",
  type: "boolean",
  default: false
});
  • Implement the survey.onTextMarkdown function to add a special character (#) to a page's navigtion title if a page contains errors.
survey.onTextMarkdown.add((sender, options) => {
    const el = options.element;
    console.log(
      "name: " +
        options.name +
        ", text: " +
        options.text +
        ", element type: " +
        el.getType()
    );
    if (!el || el.getType() !== "page") return;

    if (options.name === "navigationTitle") {
      const page = el;
      const pi = page.getProgressInfo();
      const isCompleted = pi.questionCount === pi.answeredQuestionCount;
      let hasErrors = false;
      const questions = page.questions;
      for (let i = 0; i < questions.length; i++) {
        if (questions[i].errors.length > 0) {
          hasErrors = true;
          break;
        }
      }
      let html = "";
      if (hasErrors && !el.errorMarkExists) {
        el.errorMarkExists = true;
      } else if (!hasErrors && el.errorMarkExists) {
        el.errorMarkExists = false;
      }

      if (el.errorMarkExists) {
        if (options.text.indexOf("#") < 0) {
          html = options.text + "#";
        } else {
          html = options.text;
        }
      } else {
        html = options.text.replace("#", "");
      }

      if (!isCompleted) {
        html = "<strong>" + html + "</strong>";
      }
      options.html = html;
    }
});

Now, when a user attempts to complete a survey which contains errors, an error indicator appears within Table Of Contents.
image

@JaneSjs
Copy link
Contributor Author

JaneSjs commented Sep 12, 2024

With v1.11.14, it is possible to override an item component template for a Table of Contents.

The following demo shows how to implement a custom TOC item and:

  • Display information about the answered and total questions per page.
  • Highlight a TOC item with Red/Yellow/Green depending on the number of answered questions.
    image

Follow these steps:

  1. Implement a component that renders item markup.
    The component accepts the item configuration object as a prop. You can use its item property to access the IAction which corresponds to the current page item within a TOC. Use this object to retrieve information about the current page and its answered and total question count.

  2. Register the component so that it can be accessed by name.

In React and other JS applications, register the component in ReactElementFactory as shown in the CustomTocItem.jsx file. In Angular, register the component in AngularComponentFactory as shown in the toc-custom-item.component.ts file. In Vue, implement the CustomTocItem component as shown in the CustomTocItem.vue file and register it within application components.

  1. Obtain the Table of Contents navigation element and set the itemComponent property to the custom component name.
survey.findLayoutElement("toc-navigation").data.listModel.itemComponent = "sv-custom-toc-item";

@JaneSjs JaneSjs closed this as completed Sep 12, 2024
@forat98
Copy link

forat98 commented Dec 31, 2024

@JaneSjs i'm try to use above code but the Property 'locOwner' does not exist on type 'ILocalizableOwner' return this.model.owner.locOwner
also this Property 'getPageByName' does not exist on type 'ILocalizableOwner'

  • return this.survey.getPageByName(pageName)

@JaneSjs
Copy link
Contributor Author

JaneSjs commented Jan 1, 2025

Hi @forat98,
I tested this React and Angular demos. A table of contents with a custom item component appears correctly.

Would you clarify which JS platform you're using and which example you tried?

@JaneSjs JaneSjs reopened this Jan 1, 2025
@JaneSjs JaneSjs self-assigned this Jan 1, 2025
@forat98
Copy link

forat98 commented Jan 2, 2025

i'm using angular platform , but see even if in your demo you see return this.model.owner.locOwner; "Property 'locOwner' does not exist on type 'ILocalizable Owner'.typescript(2339) "

@JaneSjs JaneSjs added the v2.0+ label Jan 2, 2025
@JaneSjs
Copy link
Contributor Author

JaneSjs commented Jan 2, 2025

Hi @forat98,
Thank you for the update. To solve the issue, update the toc-custom-item.component.ts as follows:

get survey() {
   return this.model.owner['locOwner'];
}

Meanwhile, take note that this code uses non-documented API. We'll consider adding a public API for implelenting a custom item component.

Thank you

@forat98
Copy link

forat98 commented Feb 19, 2025

I'm encountering an issue when trying to create a custom component in my Angular application using SurveyJS. The error message is as follows:

Can't create component with name: sv-custom-toc-item and default: undefined
at DynamicComponentDirective.createComponent (survey-angular-ui.js:214:19)
at DynamicComponentDirective.ngOnChanges (survey-angular-ui.js:199:18)
at DynamicComponentDirective.rememberChangeHistoryAndInvokeOnChangesHook

It occurs when I try to use `sv-custom-toc-item`. Could you provide guidance on what might be causing this issue? I'm using the latest version of SurveyJS

@JaneSjs JaneSjs removed the v2.0+ label Mar 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement user issue An issue or bug reported by users
Projects
None yet
Development

No branches or pull requests

2 participants