<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1180</guid>
      <link>https://shazwazza.com/post/reference-the-current-form-controller-in-angularjs/</link>
      <category>Web Development</category>
      <title>Reference the current form controller in AngularJS</title>
      <description>&lt;p&gt;I previously wrote a post about &lt;a href="http://shazwazza.com/post/Listening-for-validation-changes-in-AngularJS"&gt;Listening for validation changes in AngularJS&lt;/a&gt; which with my knowledge at that time required a handy hack to get a reference to the currently scoped form controller (ngForm) for a given input control. I also complained a bit that it seemed that angular didn’t really provide a way to reference the current form controller without this little hack… well, it turns out I was wrong! :)&lt;/p&gt; &lt;p&gt;AngularJS seems kind of like ASP.Net MVC in the early days when there wasn’t much documentation…&amp;nbsp; It definitely pays off to read through the source code to figure out how to do more complicated things. I had a bit of a ‘light bulb’ moment when I realized that ngForm was itself a directive/controller and had recently noticed that the ‘require’ parameter of setting up a directive allows you to search for controllers in the current directives ancestry (i.e. prefix the required controller with a hat: ^ )&lt;/p&gt; &lt;h2&gt;What does the require parameter of a directive do?&lt;/h2&gt; &lt;p&gt;Lets face it, the &lt;a href="http://docs.angularjs.org/guide/directive" target="_blank"&gt;directive documentation&lt;/a&gt; for AngularJS is in desperate need of being updated so that human beings can understand it (as noted by the many comments at the bottom). So I’ll try to explain what the ‘require’ parameter actually does and how to use it. &lt;/p&gt; &lt;p&gt;We’ll create a simple custom validation directive which will invalidate a field if the value is “blah”&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; blahValidator() {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; {
        require: &lt;span class="str"&gt;'ngModel'&lt;/span&gt;,
        link: &lt;span class="kwrd"&gt;function&lt;/span&gt;(scope, elm, attr, ctrl) {
            
            &lt;span class="kwrd"&gt;var&lt;/span&gt; validator = &lt;span class="kwrd"&gt;function&lt;/span&gt;(value) {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (ctrl.$viewValue == &lt;span class="str"&gt;"blah"&lt;/span&gt;) {
                    ctrl.$setValidity(&lt;span class="str"&gt;'blah'&lt;/span&gt;, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt; {
                    ctrl.$setValidity(&lt;span class="str"&gt;'blah'&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;);
                    &lt;span class="kwrd"&gt;return&lt;/span&gt; value;
                }
            };

            ctrl.$formatters.push(validator);
            ctrl.$parsers.push(validator);
        }
    };
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;You’ll notice that we have a ‘require’ parameter specified for ‘ngModel’. What is happening here is that when we assign this directive to an input field, angular will ensure that the input field also has a defined ng-model attribute on it as well. Then angular will pass in the instance of the ng-model controller to the ‘ctrl’ parameter of the link function.&lt;/p&gt;
&lt;p&gt;So, the ‘require’ parameter dictates what the ‘ctrl’ parameter of the link function equals. &lt;/p&gt;
&lt;p&gt;You can also require multiple controllers:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate-import/image_34.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="https://shazwazza.com/media/articulate-import/image_thumb_32.png" width="462" height="138"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE: the ctrl/ctrls parameter in the above 2 examples can be called whatever you want&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Special prefixes&lt;/h2&gt;
&lt;p&gt;Angular has 2 special prefixes for the ‘require’ parameter: &lt;/p&gt;
&lt;p&gt;^ = search the current directives ancestry for the controller&lt;/p&gt;
&lt;p&gt;? = don’t throw an exception if the required controller is not found, making it ‘optional’ not a requirement&lt;/p&gt;
&lt;p&gt;You can also combine them so angular will search the ancestry but it can be optional too such as: ^?ngController'&lt;/p&gt;
&lt;p&gt;In the above example, the blahValidator will only work if the directive is declared inside of an ng-controller block.&lt;/p&gt;
&lt;h2&gt;Referencing the current ng-form&lt;/h2&gt;
&lt;p&gt;Given the above examples, and knowing the ngForm itself is a controller we should be able to just make a requirement on ngForm and have it injected into the directive. BUT, it wont work the way you expect. For some reason angular references the ngForm controller by the name “form” which i discovered by browsing the source of angular.&lt;/p&gt;
&lt;p&gt;So now its easy to get a reference to the containing ngForm controller, all you need to do is add a ‘require’ parameter to your directive that looks like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;require: '^form'&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
and it will be injected into your ctrl parameter of your link function.</description>
      <pubDate>Thu, 23 Mar 2023 15:08:08 Z</pubDate>
      <a10:updated>2023-03-23T15:08:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1238</guid>
      <link>https://shazwazza.com/post/listening-for-validation-changes-in-angularjs/</link>
      <category>Web Development</category>
      <title>Listening for validation changes in AngularJS</title>
      <description>&lt;p&gt;In some applications it can be really useful to have controllers listen for validation changes especially in more complicated AngularJS apps where ‘ng-repeat’ is used to render form controls. There’s plenty of cases where a parent scope might need to know about validation changes based on child scopes… one such case is a validation summary. There’s a couple ways to implement this (and probably more) but they all seem a bit hacky such as:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Apply a $watch to the current form object’s $valid property in the parent scope, then use jQuery to look for elements that have a class like ‘invalid’  &lt;ul&gt; &lt;li&gt;You could then use the scope() function on the DOM element that ng-repeat is used on to get any model information about the invalid item&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;In child scopes you could apply a $watch to individual form elements’ $valid property then change the $parent scope’s model values to indicate validation changes&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Instead what I wanted to achieve was a re-usable way to ‘bubble’ up validation changes from any scope’s form element to ancestor scopes without having to do any of the following:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;No jquery DOM selection  &lt;li&gt;No hard coding of form names to access the validation objects  &lt;li&gt;No requirement to modifying other scopes’ values&lt;/li&gt;&lt;/ul&gt; &lt;h2&gt;Implementation&lt;/h2&gt; &lt;p&gt;The way I went about this was to create a very simple custom directive which I’ve called ‘val-bubble’ since it has to do with validation and it ‘bubbles’ up a message to any listening scopes. An input element might then look like this:&lt;/p&gt; &lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 200px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;name&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="FirstName"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="text"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;required&lt;/span&gt; &lt;span style="color: #ff0000"&gt;val-bubble&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;Then in an outer scope I can then listen for validation changes and do whatever I want with the result:&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 200px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;scope.$on(&lt;span style="color: #006080"&gt;"valBubble"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(evt, args) {&lt;br&gt;    alert(&lt;span style="color: #006080"&gt;"Validation changed for field "&lt;/span&gt; + args.ctrl.$name + &lt;span style="color: #006080"&gt;". Valid? "&lt;/span&gt; + args.isValid);&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;The args object contains these properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;isValid = is the field valid 
&lt;li&gt;ctrl = the current form controller object for the field 
&lt;li&gt;scope = the scope bound to the field being validated 
&lt;li&gt;element = the DOM element of the field being validated 
&lt;li&gt;expression = the current $watch expression used to watch this fields validation changes&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;With all of that information you can easily adds some additional functionality to your app based on the current validating inputs such as a validation summary or whatever.&lt;/p&gt;
&lt;h2&gt;Custom directive&lt;/h2&gt;
&lt;p&gt;The val-bubble custom directive is pretty simple, here’s the code and an explanation below:&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 500px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;app.directive(&lt;span style="color: #006080"&gt;'valBubble'&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (formHelper) {&lt;br&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; {&lt;br&gt;        require: &lt;span style="color: #006080"&gt;'ngModel'&lt;/span&gt;,&lt;br&gt;        restrict: &lt;span style="color: #006080"&gt;"A"&lt;/span&gt;,&lt;br&gt;        link: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (scope, element, attr, ctrl) {&lt;br&gt;&lt;br&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!attr.name) {&lt;br&gt;                &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #006080"&gt;"valBubble must be set on an input element that has a 'name' attribute"&lt;/span&gt;;&lt;br&gt;            }&lt;br&gt;                &lt;br&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; currentForm = formHelper.getCurrentForm(scope);&lt;br&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!currentForm || !currentForm.$name)&lt;br&gt;                &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #006080"&gt;"valBubble requires that a name is assigned to the ng-form containing the validated input"&lt;/span&gt;;&lt;br&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;//watch the current form's validation for the current field name&lt;/span&gt;&lt;br&gt;            scope.$watch(currentForm.$name + &lt;span style="color: #006080"&gt;"."&lt;/span&gt; + ctrl.$name + &lt;span style="color: #006080"&gt;".$valid"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (isValid, lastValue) {&lt;br&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (isValid != undefined) {&lt;br&gt;                    &lt;span style="color: #008000"&gt;//emit an event upwards &lt;/span&gt;&lt;br&gt;                    scope.$emit(&lt;span style="color: #006080"&gt;"valBubble"&lt;/span&gt;, {&lt;br&gt;                        isValid: isValid,       &lt;span style="color: #008000"&gt;// if the field is valid&lt;/span&gt;&lt;br&gt;                        element: element,       &lt;span style="color: #008000"&gt;// the element that the validation applies to&lt;/span&gt;&lt;br&gt;                        expression: &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.exp,   &lt;span style="color: #008000"&gt;// the expression that was watched to check validity&lt;/span&gt;&lt;br&gt;                        scope: scope,           &lt;span style="color: #008000"&gt;// the current scope&lt;/span&gt;&lt;br&gt;                        ctrl: ctrl              &lt;span style="color: #008000"&gt;// the current controller&lt;/span&gt;&lt;br&gt;                    });&lt;br&gt;                }&lt;br&gt;            });&lt;br&gt;        }&lt;br&gt;    };&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;The first thing we’re doing here is limiting this directive to be used only as an attribute and ensuring the element has a model applied to it. Then we make sure that the element has a ‘name’ value applied. After that we are getting a reference to the current form object that this field is contained within using a custom method: &lt;em&gt;formHelper.getCurrentForm&lt;/em&gt; … more on this below. Lastly we are applying a $watch to the current element’s $valid property and when this value changes we $emit an event upwards to parent/ancestor scopes to listen for. &lt;/p&gt;
&lt;h2&gt;formHelper&lt;/h2&gt;
&lt;p&gt;Above I mentioned that I wanted a re-usable solution where I didn’t need to hard code things like the current form name. &lt;span style="text-decoration: line-through"&gt;Unfortunately Angular doesn’t really provide a way to do this OOTB (as far as I can tell!)&lt;/span&gt; &lt;em&gt;(Update! see here on how to access the current form: &lt;/em&gt;&lt;a href="http://shazwazza.com/post/Reference-the-current-form-controller-in-AngularJS"&gt;&lt;em&gt;http://shazwazza.com/post/Reference-the-current-form-controller-in-AngularJS&lt;/em&gt;&lt;/a&gt;&lt;em&gt;)&lt;/em&gt; so I’ve just created a simple factory object that finds the current form object applied to the current scope. The type check is fairly rudimentary but it works, it’s simply checking each property that exists on the scope object and tries to detect the object that matches the definition of an Angular form object:&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 500px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;app.factory(&lt;span style="color: #006080"&gt;'formHelper'&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;br&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; {&lt;br&gt;        getCurrentForm: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(scope) {&lt;br&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; form = &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;br&gt;            &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; requiredFormProps = [&lt;span style="color: #006080"&gt;"$error"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$name"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$dirty"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$pristine"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$valid"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$invalid"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$addControl"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$removeControl"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$setValidity"&lt;/span&gt;, &lt;span style="color: #006080"&gt;"$setDirty"&lt;/span&gt;];&lt;br&gt;            &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; p &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; scope) {&lt;br&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_.isObject(scope[p]) &amp;amp;&amp;amp; !_.isFunction(scope[p]) &amp;amp;&amp;amp; !_.isArray(scope[p]) &amp;amp;&amp;amp; p.substr(0, 1) != &lt;span style="color: #006080"&gt;"$"&lt;/span&gt;) {&lt;br&gt;                    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; props = _.keys(scope[p]);&lt;br&gt;                    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (props.length &amp;lt; requiredFormProps.length) &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;br&gt;                    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (_.every(requiredFormProps, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(item) {&lt;br&gt;                        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; _.contains(props, item);&lt;br&gt;                    })) {&lt;br&gt;                        form = scope[p];&lt;br&gt;                        &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br&gt;                    }&lt;br&gt;                }&lt;br&gt;            }&lt;br&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; form;&lt;br&gt;        }  &lt;br&gt;    };&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;NOTE: the above code has a dependency on UnderscoreJS&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So now you can just apply the val-bubble attribute to any input element to ensure it’s validation changes are published to listening scopes!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:08 Z</pubDate>
      <a10:updated>2023-03-23T15:08:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1268</guid>
      <link>https://shazwazza.com/post/get-jquery-requests-to-play-nicely-with-angularjs-csrf-convention/</link>
      <category>Web Development</category>
      <title>Get JQuery requests to play nicely with AngularJS CSRF convention</title>
      <description>&lt;p&gt;Decided to write this quick post for anyone searching on this topic. AngularJS has it’s own convention for CSRF (Cross Site Request Forgery) protection but in some cases you’ll be calling these same server side services via JQuery so you might need to get JQuery requests to also follow Angular’s convention. &lt;/p&gt; &lt;p&gt;&lt;em&gt;For information about Angular’s CSRF protection see the “Security Considerations” part of &lt;/em&gt;&lt;a href="http://docs.angularjs.org/api/ng.$http" target="_blank"&gt;&lt;em&gt;Angular’s $http documentation&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Luckily it’s pretty darn easy to get JQuery to follow this convention too and this will also work with 3rd party plugins that use JQuery for requests like &lt;a href="https://github.com/blueimp/jQuery-File-Upload" target="_blank"&gt;Blueimp file uploader&lt;/a&gt;. The easiest way to get this done is to set the global JQuery $.ajax rules. Probably the best place to do this is in your &lt;a href="http://docs.angularjs.org/guide/module" target="_blank"&gt;Angular app.run statement&lt;/a&gt;:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.run(&lt;span class="kwrd"&gt;function&lt;/span&gt; ($cookies) {

    &lt;span class="rem"&gt;//This sets the default jquery ajax headers to include our csrf token, we&lt;/span&gt;
    &lt;span class="rem"&gt;// need to user the beforeSend method because the token might change &lt;/span&gt;
    &lt;span class="rem"&gt;// (different for each logged in user)&lt;/span&gt;
    $.ajaxSetup({
        beforeSend: &lt;span class="kwrd"&gt;function&lt;/span&gt; (xhr) {
            xhr.setRequestHeader(&lt;span class="str"&gt;"X-XSRF-TOKEN"&lt;/span&gt;, $cookies[&lt;span class="str"&gt;"XSRF-TOKEN"&lt;/span&gt;]);
        }
    }); 
});&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
That’s it! &lt;/p&gt;
&lt;p&gt;&lt;em&gt;It’s important to note to set the header using beforeSend, if you just set $.ajax options ‘headers’ section directly that means the header cannot be dynamic – which you’ll probably want if you have users logging in/out.&lt;/em&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:08 Z</pubDate>
      <a10:updated>2023-03-23T15:08:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1292</guid>
      <link>https://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/</link>
      <category>Web Development</category>
      <title>Uploading files and JSON data in the same request with Angular JS</title>
      <description>&lt;p&gt;I decided to write a quick blog post about this because much of the documentation and examples about this seems to be a bit scattered. What this achieves is the ability to upload any number of files with any other type of data in &lt;strong&gt;one&lt;/strong&gt; request. For this example we’ll send up JSON data along with some files.&lt;/p&gt; &lt;h2&gt;File upload directive&lt;/h2&gt; &lt;p&gt;First we’ll create a simple custom file upload angular directive&lt;/p&gt; &lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; height: 261px; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 420px; width: 97.99%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; height: 243px; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;app.directive(&lt;span style="color: #006080"&gt;'fileUpload'&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; () {&lt;br&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; {&lt;br&gt;        scope: &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;,        &lt;span style="color: #008000"&gt;//create a new scope&lt;/span&gt;&lt;br&gt;        link: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (scope, el, attrs) {&lt;br&gt;            el.bind(&lt;span style="color: #006080"&gt;'change'&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;) {&lt;br&gt;                &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; files = &lt;span style="color: #0000ff"&gt;event&lt;/span&gt;.target.files;&lt;br&gt;                &lt;span style="color: #008000"&gt;//iterate files since 'multiple' may be specified on the element&lt;/span&gt;&lt;br&gt;                &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; i = 0;i&amp;lt;files.length;i++) {&lt;br&gt;                    &lt;span style="color: #008000"&gt;//emit event upward&lt;/span&gt;&lt;br&gt;                    scope.$emit(&lt;span style="color: #006080"&gt;"fileSelected"&lt;/span&gt;, { file: files[i] });&lt;br&gt;                }                                       &lt;br&gt;            });&lt;br&gt;        }&lt;br&gt;    };&lt;br&gt;});&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;The usage of this is simple:&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 200px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="file"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;file-upload&lt;/span&gt; &lt;span style="color: #ff0000"&gt;multiple&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;The ‘multiple’ parameter indicates that the user can select multiple files to upload which this example fully supports.&lt;/p&gt;
&lt;p&gt;In the directive we ensure a new scope is created and then listen for changes made to the file input element. When changes are detected with emit an event to all ancestor scopes (upward) with the file object as a parameter.&lt;/p&gt;
&lt;h2&gt;Mark-up &amp;amp; the controller&lt;/h2&gt;
&lt;p&gt;Next we’ll create a controller to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a model to bind to 
&lt;li&gt;Create a collection of files 
&lt;li&gt;Consume this event so we can assign the files to&amp;nbsp; the collection 
&lt;li&gt;Create a method to post it all to the server&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;NOTE: I’ve put all this functionality in this controller for brevity, in most cases you’d have a separate factory to handle posting the data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With the controller in place, the mark-up might look like this (and will display the file names of all of the files selected):&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 200px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ng-controller&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Ctrl"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;input&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="file"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;file-upload&lt;/span&gt; &lt;span style="color: #ff0000"&gt;multiple&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;ul&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ng-repeat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="file in files"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;{{file.name}}&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;li&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;ul&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;p&gt;The controller code below contains some important comments relating to how the data gets posted up to the server, namely the ‘Content-Type’ header as the value that needs to be set is a bit quirky. &lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 1000px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; Ctrl($scope, $http) {&lt;br&gt;&lt;br&gt;    &lt;span style="color: #008000"&gt;//a simple model to bind to and send to the server&lt;/span&gt;&lt;br&gt;    $scope.model = {&lt;br&gt;        name: &lt;span style="color: #006080"&gt;""&lt;/span&gt;,&lt;br&gt;        comments: &lt;span style="color: #006080"&gt;""&lt;/span&gt;&lt;br&gt;    };&lt;br&gt;&lt;br&gt;    &lt;span style="color: #008000"&gt;//an array of files selected&lt;/span&gt;&lt;br&gt;    $scope.files = [];&lt;br&gt;&lt;br&gt;    &lt;span style="color: #008000"&gt;//listen for the file selected event&lt;/span&gt;&lt;br&gt;    $scope.$on(&lt;span style="color: #006080"&gt;"fileSelected"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;event&lt;/span&gt;, args) {&lt;br&gt;        $scope.$apply(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; () {            &lt;br&gt;            &lt;span style="color: #008000"&gt;//add the file object to the scope's files collection&lt;/span&gt;&lt;br&gt;            $scope.files.push(args.file);&lt;br&gt;        });&lt;br&gt;    });&lt;br&gt;    &lt;br&gt;    &lt;span style="color: #008000"&gt;//the save method&lt;/span&gt;&lt;br&gt;    $scope.save = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;br&gt;        $http({&lt;br&gt;            method: &lt;span style="color: #006080"&gt;'POST'&lt;/span&gt;,&lt;br&gt;            url: &lt;span style="color: #006080"&gt;"/Api/PostStuff"&lt;/span&gt;,&lt;br&gt;            &lt;span style="color: #008000"&gt;//IMPORTANT!!! You might think this should be set to 'multipart/form-data' &lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// but this is not true because when we are sending up files the request &lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// needs to include a 'boundary' parameter which identifies the boundary &lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// name between parts in this multi-part request and setting the Content-type &lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// manually will not set this boundary parameter. For whatever reason, &lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// setting the Content-type to 'false' will force the request to automatically&lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// populate the headers properly including the boundary parameter.&lt;/span&gt;&lt;br&gt;            headers: { &lt;span style="color: #006080"&gt;'Content-Type'&lt;/span&gt;: &lt;span style="color: #0000ff"&gt;false&lt;/span&gt; },&lt;br&gt;            &lt;span style="color: #008000"&gt;//This method will allow us to change how the data is sent up to the server&lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// for which we'll need to encapsulate the model data in 'FormData'&lt;/span&gt;&lt;br&gt;            transformRequest: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (data) {&lt;br&gt;                &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; formData = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; FormData();&lt;br&gt;                &lt;span style="color: #008000"&gt;//need to convert our json object to a string version of json otherwise&lt;/span&gt;&lt;br&gt;                &lt;span style="color: #008000"&gt;// the browser will do a 'toString()' on the object which will result &lt;/span&gt;&lt;br&gt;                &lt;span style="color: #008000"&gt;// in the value '[Object object]' on the server.&lt;/span&gt;&lt;br&gt;                formData.append(&lt;span style="color: #006080"&gt;"model"&lt;/span&gt;, angular.toJson(data.model));&lt;br&gt;                &lt;span style="color: #008000"&gt;//now add all of the assigned files&lt;/span&gt;&lt;br&gt;                &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; i = 0; i &amp;lt; data.files; i++) {&lt;br&gt;                    &lt;span style="color: #008000"&gt;//add each file to the form data and iteratively name them&lt;/span&gt;&lt;br&gt;                    formData.append(&lt;span style="color: #006080"&gt;"file"&lt;/span&gt; + i, data.files[i]);&lt;br&gt;                }&lt;br&gt;                &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; formData;&lt;br&gt;            },&lt;br&gt;            &lt;span style="color: #008000"&gt;//Create an object that contains the model and files which will be transformed&lt;/span&gt;&lt;br&gt;            &lt;span style="color: #008000"&gt;// in the above transformRequest method&lt;/span&gt;&lt;br&gt;            data: { model: $scope.model, files: $scope.files }&lt;br&gt;        }).&lt;br&gt;        success(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (data, status, headers, config) {&lt;br&gt;            alert(&lt;span style="color: #006080"&gt;"success!"&lt;/span&gt;);&lt;br&gt;        }).&lt;br&gt;        error(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (data, status, headers, config) {&lt;br&gt;            alert(&lt;span style="color: #006080"&gt;"failed!"&lt;/span&gt;);&lt;br&gt;        });&lt;br&gt;    };&lt;br&gt;};&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;
&lt;h2&gt;Handling the data server-side&lt;/h2&gt;
&lt;p&gt;This example shows how to handle the data on the server side using ASP.Net WebAPI, I’m sure it’s reasonably easy to do on other server-side platforms too.&lt;/p&gt;
&lt;div id="codeSnippetWrapper" style="overflow: auto; cursor: text; font-size: 8pt; border-top: silver 1px solid; font-family: 'Courier New', courier, monospace; border-right: silver 1px solid; border-bottom: silver 1px solid; padding-bottom: 4px; direction: ltr; text-align: left; padding-top: 4px; padding-left: 4px; margin: 20px 0px 10px; border-left: silver 1px solid; line-height: 12pt; padding-right: 4px; max-height: 500px; width: 97.5%; background-color: #f4f4f4"&gt;&lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;p&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; async Task&amp;lt;HttpResponseMessage&amp;gt; PostStuff()&lt;br&gt;{&lt;br&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!Request.Content.IsMimeMultipartContent())&lt;br&gt;    {&lt;br&gt;        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseException(HttpStatusCode.UnsupportedMediaType);&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    var root = HttpContext.Current.Server.MapPath(&lt;span style="color: #006080"&gt;"~/App_Data/Temp/FileUploads"&lt;/span&gt;);&lt;br&gt;    Directory.CreateDirectory(root);&lt;br&gt;    var provider = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MultipartFormDataStreamProvider(root);&lt;br&gt;    var result = await Request.Content.ReadAsMultipartAsync(provider);&lt;br&gt;    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (result.FormData[&lt;span style="color: #006080"&gt;"model"&lt;/span&gt;] == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;br&gt;    {&lt;br&gt;        &lt;span style="color: #0000ff"&gt;throw&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseException(HttpStatusCode.BadRequest);&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    var model = result.FormData[&lt;span style="color: #006080"&gt;"model"&lt;/span&gt;];&lt;br&gt;    &lt;span style="color: #008000"&gt;//TODO: Do something with the json model which is currently a string&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #008000"&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span style="color: #008000"&gt;//get the files&lt;/span&gt;&lt;br&gt;    &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var file &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; result.FileData)&lt;br&gt;    {                &lt;br&gt;        &lt;span style="color: #008000"&gt;//TODO: Do something with each uploaded file&lt;/span&gt;&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Request.CreateResponse(HttpStatusCode.OK, &lt;span style="color: #006080"&gt;"success!"&lt;/span&gt;);&lt;br&gt;}&lt;/p&gt;&lt;/pre&gt;&lt;br&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:08 Z</pubDate>
      <a10:updated>2023-03-23T15:08:08Z</a10:updated>
    </item>
  </channel>
</rss>