{"pageProps":{"locale":{"code":"en","domain":"frenchstack.com","lang":"en-US","json":{"TRANSLATE":"Translate into","EN":"English","FR":"French","NO_TRANSLATION_AVAILABLE":"No translation available","PROFILE_OF":"Profile of","FILTER_BY_TAG":"Filter by tag","REMOVE_FILTER":"Remove filter","RESULT":"Result","RESULTS":"Results","FORM_CONTACT_SUPPORT":"Support","FORM_CONTACT_SALES":"Sales","FORM_CONTACT_BUGS":"Report a bug","FORM_LOADING":"Loading","FORM_SEND":"Send","FORM_VERIFY":"Verify","FORM_NAME":"Name","FORM_TOPIC":"Subject","FORM_PHONE":"Phone","FORM_EMAIL":"Email","FORM_MESSAGE":"Message","FORM_DOMAIN_PLACEHOLDER":"example.com","FORM_DOMAIN_AVAILABLE":"Congrats, <span data-selector='domain'></span> is available!","FORM_DOMAIN_TAKEN":"Sorry, <span data-selector='domain'></span> is taken.","SUBSCRIBE":"Subscribe","SUCCESS_CONTACT":"Your message has been successfully sent! We'll be in touch soon.","SOMETING_WENT_WRONG":"Oops, something went wrong. Please try again later.","PERFORMANCE":"Performance","ACCESSIBILITY":"Accessibility","BEST_PRACTICES":"Best Practices","SEO":"SEO","MOBILE":"Mobile","TABLET":"Tablet","DESKTOP":"Desktop","VISITORS":"Visitors","ENGAGEMENT":"Engagement","CONVERSIONS":"Conversions","JAN":"Jan","FEB":"Feb","MAR":"Mar","APR":"Apr","MAY":"May","JUN":"Jun","JUL":"Jul","AUG":"Aug","SEP":"Sep","OCT":"Oct","NOV":"Nov","DEC":"Dec","METHOD_PHONE":"Phone","METHOD_EMAIL":"Email","FOOTER_TAGLINE":"We create unique digital experiences for brands and businesses.","LOOP_ACTOR_AGENT":"AI agent","LOOP_STEPS":"Steps","LOOP_REPEATED":"repeated","AND":"and"},"subdomains":{"blog":"blog","clients":"clients","videos":"videos","services":"services"},"ogSection":"Technology"},"slugs":["en","blog","angular"],"component":"paging","articles":[{"id":"content/articles/en/angular-form-validation-compare-multiple-fields.mdx","heroSection":{"heroTitle":"Comparing Multiple Fields","heroSubtitle":"","heroBadge":"Angular Form Validation","heroColoredWords":"1","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"How to validate two form fields by comparing them?"}]},{"type":"p","children":[{"type":"text","text":"Let's verify multiple fields with a high-level validator!"}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/angular-form-validation.png","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(180deg, transparent 0%, #0e256ddb 17%, #ff4444db 120%)","heroMaxWidth":"","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"angular form validation","imageWidth":1344,"imageHeight":768},"seoSection":{"metaTitle":"Angular Form Validation: Comparing Multiple Fields","metaDescription":"How to validate two form fields by comparing them? Let's verify multiple fields with a high-level validator!","metaTags":"form, angular, validation, angular-validation","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2024-12-07T00:09:54.046Z","localeCode":"en","slug":"angular-form-validation-compare-multiple-fields","url":"/en/blog/angular-form-validation-compare-multiple-fields","ogId":"angular-form-validation-compare-multiple-fields-blog-en","ogImagePath":"/og/angular-form-validation-compare-multiple-fields-blog-en.png","type":"Article","title":"Comparing Multiple Fields with Angular","subtitle":"","browserUrl":"","textPreview":{"type":"root","children":[]},"subdomainKey":"blog","subdomain":"blog","draft":false,"logoAlt":"","logoWidth":0,"logoHeight":0,"body":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"Suppose our form has date fields "},{"type":"text","text":"startDate","code":true},{"type":"text","text":" and "},{"type":"text","text":"endDate","code":true},{"type":"text","text":", and we want to ensure that "},{"type":"text","text":"startDate","code":true},{"type":"text","text":" must be before "},{"type":"text","text":"endDate","code":true},{"type":"text","text":"."}]},{"type":"p","children":[{"type":"text","text":"To implement validations containing one or more sibling controls, we need to define the validation function at a higher level than the sibling controls."}]},{"type":"mdxJsxFlowElement","name":"codeHeader","children":[{"type":"text","text":""}],"props":{"filePath":"app / src / pages / form-example / form-example.component.ts","fileName":"form-example.component.ts","svgFile":"typescript"}},{"type":"code_block","lang":"typescript","value":"ngOnInit() : void\n{\n  this.formGroup = this.formBuilder.group(\n  {\n    startDate : new FormControl({\n      value    : null,\n      disabled : false\n    }, [ Validators.required ]),\n    endDate : new FormControl({\n      value    : null,\n      disabled : false\n    }, [ Validators.required ]),\n  },\n  // NOTE High-level validator\n  { validator : DateValidator.dateRangeValidator });\n}","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"Then, we define a custom validator in a separate file, for example "},{"type":"text","text":"date.validator.ts","code":true},{"type":"text","text":"."}]},{"type":"mdxJsxFlowElement","name":"codeHeader","children":[{"type":"text","text":""}],"props":{"fileName":"date.validator.ts","filePath":"app / src / shared / validators / date.validator.ts","svgFile":"typescript"}},{"type":"code_block","lang":"typescript","value":"// Angular modules\nimport { Injectable }       from '@angular/core';\nimport { AbstractControl }  from '@angular/forms';\nimport { ValidationErrors } from '@angular/forms';\n\n@Injectable({\n  providedIn : 'root'\n})\nexport class DateValidator\n{\n  constructor() {}\n\n  public static dateRangeValidator(control : AbstractControl) : ValidationErrors | null\n  {\n    // NOTE Safety check\n    if (!control.get('startDate').value || !control.get('endDate').value)\n      return null;\n\n    // NOTE Field comparison\n    // const mStart  = moment(control.get('startDate').value);\n    // const mEnd    = moment(control.get('endDate').value);\n    // const isValid = mStart.isBefore(mEnd);\n\n    // NOTE Invalid\n    if (!isValid)\n      return { invalidDateRange : true };\n\n    // NOTE Valid\n    return null;\n  }\n}","children":[{"type":"text","text":""}]},{"type":"p","children":[{"type":"text","text":"If invalid, return an error object (with any arbitrary name), such as "},{"type":"text","text":"return { invalidEndDate: true }","code":true},{"type":"text","text":"."}]},{"type":"p","children":[{"type":"text","text":"Make sure it always returns "},{"type":"text","text":"null","code":true},{"type":"text","text":" for valid or irrelevant cases, and a non-null object in cases where an error should be triggered on the "},{"type":"text","text":"formGroup","code":true},{"type":"text","text":"."}]},{"type":"p","children":[{"type":"text","text":"To display the error in our view, we use the "},{"type":"text","text":"invalidDateRange","code":true},{"type":"text","text":" key returned by our validator."}]},{"type":"mdxJsxFlowElement","name":"codeHeader","children":[{"type":"text","text":""}],"props":{"fileName":"form-example.component.html","filePath":"app / src / pages / form-example / form-example.component.html","svgFile":"html"}},{"type":"code_block","lang":"html","value":"<div *ngIf=\"formGroup.hasError('invalidDateRange')\">\n  The start date is not before the end date\n</div>","children":[{"type":"text","text":""}]}]},"dateCreate":"2021-03-17T10:46:42.000Z","dateUpdate":"2021-09-15T10:57:26.000Z","author":{"id":"content/authors/en/nicolas-roehm-bettcher.mdx","heroSection":{"heroTitle":"Nicolas Roehm","heroSubtitle":"Software Engineer","heroBadge":"","heroColoredWords":"","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"Founder of French Stack, I create complete IT solutions."}]},{"type":"p","children":[{"type":"text","text":"Full-stack developer, I mainly work on frontend projects using Angular, React, or Vue."}]},{"type":"p","children":[{"type":"text","text":"Passionate about design, here are some of my "},{"type":"a","url":"https://www.artstation.com/nicolas-roehm","title":"ArtStation - Nicolas Roehm","children":[{"type":"text","text":"graphic designs"}]},{"type":"text","text":"."}]},{"type":"mdxJsxFlowElement","name":"socialLinks","children":[{"type":"text","text":""}],"props":{"links":[{"icon":"gitHub","link":"https://github.com/NicolasRoehm"},{"icon":"stackOverflow","link":"https://stackoverflow.com/users/7462178/nicolas-roehm?tab=profile"},{"icon":"linkedIn","link":"https://en.linkedin.com/in/nicolas-roehm-bettcher"}]}}]},"heroSubtitleIsInline":true,"heroHasBackground":false,"heroImage":"/images/nicolas-roehm-bettcher.png","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(312deg, #0800ff 0%, #4300ff00 70%)","heroMaxWidth":"","heroMs":"25%","heroTitleMb":"0.5rem","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"#fff0","navbarBorderColor":"","navbarLinkActive":"#6785be","navbarLinkHover":"#6785be"},"imageAlt":"nicolas roehm bettcher","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"Nicolas Roehm, Software Engineer","metaDescription":"Passionate about computing, I design complete websites: design, development, SEO, e-reputation, e-mailing, hosting.","metaTags":"Nicolas Roehm, Software Engineer, web, mobile, website","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2024-12-09T00:39:02.584Z","localeCode":"en","slug":"nicolas-roehm-bettcher","url":"/en/nicolas-roehm-bettcher","ogId":"nicolas-roehm-bettcher-en","ogImagePath":"/og/nicolas-roehm-bettcher-en.png","type":"Author","title":"Nicolas Roehm-Bettcher","avatar":"/images/nicolas-roehm-avatar.png","lname":"Roehm","fname":"Nicolas","name":"Nicolas Roehm","translations":[{"localeCode":"fr","title":"Nicolas Roehm-Bettcher","slug":"nicolas-roehm-bettcher","url":"/fr/nicolas-roehm-bettcher"}]},"translations":[{"localeCode":"fr","title":"Comparer plusieurs champs avec Angular","slug":"angular-validation-formulaire-comparer-plusieurs-champs","url":"/fr/blog/angular-validation-formulaire-comparer-plusieurs-champs"}],"tags":[{"id":"content/tags/en/angular.mdx","localeCode":"en","title":"Angular","slug":"angular","url":"/en/blog/angular"}]}],"tag":{"id":"content/tags/en/angular.mdx","heroSection":{"heroTitle":"Angular","heroSubtitle":"","heroBadge":"","heroColoredWords":"","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"TypeScript-based open-source web application framework led by Google"}]},{"type":"p","children":[{"type":"text","text":"and by a community of individuals and corporations"}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/angular.svg","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(140deg, rgb(0,69,145,0.83) 31%, rgb(221,7,49) 100%)","heroMaxWidth":"","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"angular","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"Angular","metaDescription":"TypeScript-based open-source web application framework led by Google and by a community of individuals and corporations","metaTags":"Angular, Typescript, Material, Bootstrap","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2023-08-18T08:52:56.731Z","localeCode":"en","slug":"angular","url":"/en/blog/angular","ogId":"angular-blog-en","ogImagePath":"/og/angular-blog-en.png","type":"Tag","title":"Angular","subdomainKey":"blog","subdomain":"blog","translations":[{"localeCode":"fr","title":"Angular","slug":"angular","url":"/fr/blog/angular"}]},"tags":[{"id":"content/tags/en/angular.mdx","heroSection":{"heroTitle":"Angular","heroSubtitle":"","heroBadge":"","heroColoredWords":"","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"TypeScript-based open-source web application framework led by Google"}]},{"type":"p","children":[{"type":"text","text":"and by a community of individuals and corporations"}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/angular.svg","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(140deg, rgb(0,69,145,0.83) 31%, rgb(221,7,49) 100%)","heroMaxWidth":"","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"angular","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"Angular","metaDescription":"TypeScript-based open-source web application framework led by Google and by a community of individuals and corporations","metaTags":"Angular, Typescript, Material, Bootstrap","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2023-08-18T08:52:56.731Z","localeCode":"en","slug":"angular","url":"/en/blog/angular","ogId":"angular-blog-en","ogImagePath":"/og/angular-blog-en.png","type":"Tag","title":"Angular","subdomainKey":"blog","subdomain":"blog","translations":[{"localeCode":"fr","title":"Angular","slug":"angular","url":"/fr/blog/angular"}]},{"id":"content/tags/en/jquery.mdx","heroSection":{"heroTitle":"jQuery","heroSubtitle":"","heroBadge":"","heroColoredWords":"","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"jQuery is an open-source JavaScript library designed to simplify HTML DOM tree traversal and manipulation, as well as event handling, CSS animation, and Ajax"}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/jquery-logo.svg","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(140deg, rgba(0,69,145,0) 31%, rgba(0,174,255,100) 100%)","heroMaxWidth":"860px","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"jquery logo","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"jQuery","metaDescription":"jQuery is an open-source JavaScript library designed to simplify HTML DOM tree traversal and manipulation, event handling, CSS animation, Ajax request","metaTags":"jQuery, Javascript, library, DOM HTML","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2024-12-08T19:30:13.969Z","localeCode":"en","slug":"jquery","url":"/en/blog/jquery","ogId":"jquery-blog-en","ogImagePath":"/og/jquery-blog-en.png","type":"Tag","title":"jQuery","subdomainKey":"blog","subdomain":"blog","translations":[{"localeCode":"fr","title":"jQuery","slug":"jquery","url":"/fr/blog/jquery"}]},{"id":"content/tags/en/typescript.mdx","heroSection":{"heroTitle":"TypeScript","heroSubtitle":"","heroBadge":"","heroColoredWords":"","heroBreakTitle":"","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"Open-source typed superset of JavaScript,"}]},{"type":"p","children":[{"type":"text","text":"delivering robustness, maintainability, and software architecture excellence."}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/site-internet-web-development-agency.png","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(140deg, #1b3a6b 0%, #3178c6 100%)","heroMaxWidth":"","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"site internet web development agency","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"TypeScript","metaDescription":"Typed superset of JavaScript designed to build scalable, robust and maintainable modern web applications.","metaTags":"TypeScript, JavaScript, static typing, codebase intelligence, code quality","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2026-08-26T09:00:00.000Z","localeCode":"en","slug":"typescript","url":"/en/blog/typescript","ogId":"typescript-blog-en","ogImagePath":"/og/typescript-blog-en.png","type":"Tag","title":"TypeScript","subdomainKey":"blog","subdomain":"blog","translations":[{"localeCode":"fr","title":"TypeScript","slug":"typescript","url":"/fr/blog/typescript"}]}],"pages":[0],"curPage":1,"page":{"id":"content/subdomains/en/blog.mdx","heroSection":{"heroTitle":"Digital news","heroSubtitle":"","heroBadge":"","heroColoredWords":"2","heroBreakTitle":"","heroShape":"shiny","heroGradient":"business-gradient","heroDescription":{"type":"root","children":[{"type":"p","children":[{"type":"text","text":"Our online magazine presents new generation "},{"type":"text","text":"web trends","bold":true},{"type":"text","text":":"}]},{"type":"p","children":[{"type":"text","text":"design, SEO and SEM, marketing, development, optimization ..."}]},{"type":"p","children":[{"type":"text","text":"Discover our articles dedicated to "},{"type":"text","text":"new technologies","bold":true},{"type":"text","text":" and "},{"type":"text","text":"web standards","bold":true},{"type":"text","text":"!"}]},{"type":"p","children":[{"type":"text","text":"Subscribe via email or follow us on social networks to stay tuned about web news."}]}]},"heroSubtitleIsInline":false,"heroHasBackground":false,"heroImage":"/images/blog-news-web.jpg","heroVideoBackground":"","heroStyle":{"heroBg":"linear-gradient(353deg, rgba(255,129,0,0.64) 0%, #0018ffe0 120%)","heroMaxWidth":"","heroMs":"","heroTitleMb":"","heroTitleColor":"","heroContentBg":"","heroContentAlign":"","heroContentBlur":"","heroBlurImage":"","navbarBg":"","navbarBorderColor":"","navbarLinkActive":"","navbarLinkHover":""},"imageAlt":"blog news web","imageWidth":0,"imageHeight":0},"seoSection":{"metaTitle":"Digital news","metaDescription":"Online magazine to learn the Web, find resources, browse trends and enjoy a hot coffee","metaTags":"Web Inspiration, Tutorials, web trends","socialImageWidth":0,"socialImageHeight":0},"heroUpdatedAt":"2023-08-18T08:52:56.731Z","localeCode":"en","slug":"blog","url":"/en/blog","ogId":"blog-en","ogImagePath":"/og/blog-en.png","type":"Subdomain","title":"Blog","subdomainKey":"blog","subdomain":"blog","translations":[{"localeCode":"fr","title":"Blog","slug":"blog","url":"/fr/blog"}],"canShare":true,"canComment":true,"hasAuthor":true,"tagsInPanel":true,"cardContainer":"col-md-6","cardTemplate":"default"},"global":{"id":"content/global/en/settings.json","localeCode":"en","header":{"nav":[{"href":"index","label":"Home"},{"href":"blog","label":"Blog"},{"href":"videos","label":"Videos"},{"href":"services","label":"Services"},{"href":"clients","label":"Clients"},{"href":"about","label":"About"},{"href":"contact-us","label":"Contact"}]},"footer":{"social":[{"website":"x","account":"RoehmNicolas"},{"website":"instagram","account":"roehm.nicolas"},{"website":"facebook","account":"thefrenchstack"},{"website":"youtube","account":"@frenchstack"}],"hasSocial":true,"nav":[{"title":"French Stack","links":[{"href":"clients","label":"Clients"},{"href":"about","label":"About"},{"href":"contact-us","label":"Contact"}]},{"title":"Services","links":[{"href":"services/graphic-design","label":"Design"},{"href":"services/web-mobile-development","label":"Development"},{"href":"services/web-marketing","label":"Marketing"},{"href":"services/it-training","label":"Training"}]},{"title":"Blog","links":[{"href":"blog/angular","label":"Angular"},{"href":"blog/jquery","label":"jQuery"}]},{"title":"Videos","links":[{"href":"videos/audiovisual-marketing","label":"Audiovisual Marketing"}]}]},"bottom":{"dateCreate":"2015-12-27T05:55:00.000Z","nav":[{"href":"legal-informations","label":"Legal informations"},{"href":"privacy-policy","label":"Privacy policy"}],"hasLinks":true},"contactInfo":{"contactMethods":[{"id":"email","icon":"envelope","value":"frenchstack@gmail.com"},{"id":"phone","icon":"phone","value":"0651570751"}]}}},"__N_SSG":true}