recursive/circular template calls - html

I have a setup with Angular 2 where the home.html has a
<widgetcontainer></widgetcontainer> call, which in turn calls certain widget templates.
Those widget templates however would need to call widgetcontainer again so their sub-widgets can be displayed as well.
It looks somewhat like this:
home.html:
<div> home site specific content </div>
<ul>
<widgetcontainer *ng-for="#widget of widgetList" [containerwidget]="widget"></widgetcontainer>
</ul>
widgetcontainer.html:
<li>
<div [ng-switch]="containerwidget.type">
<p *ng-switch-when="1"><widget1 [widget]="containerwidget"></widget1></p>
<p *ng-switch-when="2"><widget2 [widget]="containerwidget"></widget2></p>
<p *ng-switch-default>Error in widget-data</p>
</div>
</li>
now widget1 and widget2 are pretty much identical except for the first bit of content:
<div> widget 1 or 2 specific content </div>
<div *ng-if="widget.widgetSubList">
<div class="widget-sub-listing" *ng-for="#widget of widgetlocal.widgetSubList">
<widgetcontainer *ng-for="#widget of widgetlocal.widgetSubList" [containerwidget]="widget"></widgetcontainer>
</div>
</div>
The reason why I need to do it this way is that widget1 can contain a series of widget2 (and others) which in turn can contain widget1 again.
The .ts counterparts of each widget contain the required #Input part, so if I leave out the call to widgetcontainer, it does work just fine, though of course therefor can't display the subwidgets anymore. Reading out the subwidgets works as well, tested that with console.logs.
I found similiar problems like this one: How do I inject a parent component into a child component?
where, from what I gathered, the problem is solved by importing Input and forwardRef and using
constructor( #Inject(forwardRef(() => widgetcontainer)) private _parent: widgetcontainer) { }
in the children, in my case widget 1 and 2. I tried that as well, but I still get an error. Importing widgetcontainer to the widget.ts files works without trouble, adding it to the directives or adding the <widgetcontainer></widgetcontainer> call into the html of widget1 or 2 breaks the program and throws me the error message:
EXCEPTION: TypeError: Die Eigenschaft "length" eines undefinierten oder Nullverweises kann nicht abgerufen werden. in [null]
As a little translation-attempt: it basicly says
the property "length" of an undefined or null-reference can not be called. in [null]
And I can't locate where exactly the error is. Considering it works without adding widgetcontainer to the directives in widget1 or 2, I would guess that is where the whole thing breaks though.
Previously I had a similiar error, though instead of length it stated to have failed calling forEach though now I am unable to replicate the error.
From what I have been reading up on the problem is the circular reference/call of the <widgetcontainer></widgetcontainer> template. It should be possible to have it work, though it needs a stopping-condition to not turn into an infinite loop. Therefor I already have the *ng-if condition in my widget1 and 2 which is tested already with simple listings of the subwidget IDs and worked just fine as a condition.
The question is now where am I going wrong here? Or how can I get the circular call to work?

Related

How to get a I18n variable value I can return to my Angular parent component?

I'm new to Angular and I just put in place an i18n (2 languages) system for a website I am creating. Everything works properly but in order to switch from one language to another in my header, I feel stuck.
I followed the Angular documentation to transfer my variables from child to parent component and I ended with this:
<input type="text" id="item-input" #lang>
<button type="button" (click)="changeChosenLang(lang.value)">
{{ 'global.lang' | translate }}
</button>
As you can see, I write my language in the input form and I send it to the proper component with a button. What I wanted was to click on my 'global.lang' text and to be able to send its value to the parent component, since the value is the language which is not actually used.
I don't know how to put my 'global.lang' text in a variable, neither what kind of balise I can use. Also I didn't know how to summarize my problem to search for it on StackOverflow so if you know a similar post, don't hesitate to post the link.
Thank you for your reading!
I found a less tortured way (poor brain) to have the result I wanted:
<span (click)="changeChosenLang()">
{{ 'global.lang' | translate }}
</span>
First I temporary changed my button to a span balise and I deleted the parameter from my changeChosenLang() function. Then, I transferred a variable 'lang' from my parent component to this one, witch contains the value of the language chosen in my app constructor. At each click, I change its value in my changeChosenLang() function and everything works great!
I hope it can help someone someday. The moral of this post is: the simpler, the better! Have a good day.

Vue: Chrome tab crashes when trying to display a long string

I have a vue component whose purpose is to display a string.
The string can be very long - the one I tested had about 3 megabytes.
When trying to display string of such size the chrome tab crashes with its CPU usage going up to 100%. The console is clear.
Here's the simplified code of the component:
<template>
<div>
{{ output }}
</div>
</template>
<script>
export default {
name: "OutputField",
props: ['output']
}
</script>
The problem does not occur on Firefox.
It also disappears once the {{ output }} is commented out - which leads me to believe it has nothing to do with the logic of parent component.
Last but not least, when directly inserting the string into the innerHTML of the div, it is shown correctly even on Chrome.
I would really appreciate an explanation of this behavior and suggestions on how to display the string in a way that won't lead to it. Thanks in advance!
After looking into the problem more I managed to narrow down the possible cause to specific string messing up Vuetify's behavior in Chrome.
Created a separate question, as adding the details here would make the initial one hard to read.
It is available here: ­ inserted into string in Vuetify crashing Chrome tab
Since the only purpose of your component is to display a value passed as a prop, you should use a functional component. It basically is a component that gets rid of the overhead that vue needs to have a state (data, methods, etc.). Instead, it will deal only with props passed to it.
You can set it up like this:
ChildComponent.vue
<template functional>
<div>{{ props.outputVal }}</div>
</template>
ParentComponent.vue
<ChildComponent outputVal="stringToDisplay">
It probably won't make the page respond instantly still, as that's a lot of data to display, but it should increase the performance by a lot and at least allow the string to display.
Here is an example of it which displays a huge string:
https://codesandbox.io/s/vue-functional-components-xbpci

How to see if Chrome manipulates HTML by itself?

If you forget to close a HTML-Tag, Chrome will validate your code and try to fix problems like this.
I had a major problem because I forgot a closing Form-Tag, and instead of closing it correctly, Chrome deleted a following form, not the inputs, simply the Form-Tags.
When I looked at the Source Code itself, the Form-Tag was there, but not in the Elements-Tab in the console.
So at first, I thought it must have something to do with some JS deleting this DOM-Node and set a DOM-Breakpoint to find the script.
To cut a long story short, it took me hours to find out, that no JS deleted my form, but Chrome itself thought: There is a missing so I delete some other to fix that...
Is there any possibilty to see if Chrome automatically changes your DOM?
Thank You!
The browser Engine does indeed. They use string replace methods, although it happens internally.
<div>
</div>> // mistake
<div> //missing end tag
<div></div>
---------------------------------------------------
Methods
file=file.stringreplace('>>', '>')
an uneven count will add the missing div just after the next beginning div and conditionally if the missing is not found by the end of the file:
file=file.stringreplace('
<div>', '</div>
<div>')
The Parsing Engine after the missing and broken tags are repaired then parses the file and can then with a positive count set the screens GUI widgets by opening and closing tags as GUI Frames. It does this by adding tokens delimiters to the actual div tags making them easily distinguished from each other.
<div1s>
</div1e>
<div1s>//section columns
<div2s></div2e>
<div2s></div2e>
<div2s></div2e>
</div1e>
<div1s>Footer</div1e>
-----------------------------------------------------
The GUI Frame Tokens
for each "<dive1>"{
FrameCreate(CSS--ATTRIBUTES FROM ASSOCIATIVE ARRAYS--)
//the GUI Frame Widgets VERTICAL SECTIONS
}
//Next it finds the nested divs2 and embeds these into the thir parents above but with embedded Text Widgets also.
FrameTextBoxCreate(--CSS MATED ATTRIBUTES RULES--)
div3 etc------and so on.
In fact it is in the WebView GUI Widget Sets in its customized Mosaic Canvas Widget Sets in Chrome would be where they are repaired.

MediaWiki: how to prevent template from inserting white space?

Today, I tried to create a template on Portuguese Wikipedia inside one of my subpages. It works fine with this code:
<includeonly>'''{{{num}}}''': <span style="font-family:monospace;">{{{date}}}</span> — [[{{{title}}}]]<!--
--> {{#if:{{{faults|}}}<!--
-->|({{{faults}}})<!--
--->|}}<br /></includeonly>
This code creates items like this:
81: 28/feb — Der heimliche Aufmarsch gegen die Sowjetunion (one source)
But, I want to do more! The purpose of creating this template isn't just to set the date to monospace fonts... I want to add support for information about translations, and about deletions. Every time I tried to add text about deletions (you can check in the page history), the space between the lines got enormous, making the "lists" very, very ugly...
For example, this is one of the solutions I tried to add deletion information:
<includeonly>'''{{{num}}}''': <span style="font-family:monospace;">{{{date}}}</span> — [[{{{title}}}]]<!--
--> {{#if:{{{faults|}}}<!--
-->|({{{faults}}})<!--
-->|}}<!--
-->{{#if:{{{Speedy-del|{{{Semi-speedy-del|{{{Consensus-del|}}}}}}}}}|
{{#if:{{{Speedy-del|}}}<!--
-->|<div style="margin-left:2em">✘ <small>Speedy deletion denied by {{{Speedy denier}}} on {{{Speedy date}}}</small></div><!--
-->|}}
{{#if:{{{Semi-speed-del|}}}<!--
-->|<div style="margin-left:2em">✘ <small>Semi-speedy deletion denied by {{{Semi-speedy denier}}} on {{{Semi-speedy date|}}}</small></div><!--
-->|}}
{{#if:{{{Consensus-del|}}}|<!--
--><div style="margin-left:2em">✘ <small>Consensus deletion denied on {{{Consensus date|}}}</small></div><!--
-->|}}
|<br />}}</includeonly>
Why is this happening to me? I could not find any typo. So the problem must be logical, and I gave up trying to find a solution alone. My logic must be broken.
You can use HTML comments if you want to make sure there is no extra output from your template, but still need linebreaks etc for readability:
<includeonly><!--
-->'''{{{num}}}''': {{{date}}}<!--
-->[[{{{title}}}]]<!--
-->{{#if:{{{faults|}}}| ({{{faults}}})|}}<br><!--
--></includeonly>

MVC Sitemap renders empty when the current action is not in the Mvc.sitemap file

Is it possible to force the sitemap control to render the menu when the current action is not listed in the MVC.sitemap file?
I have a simple top nav. When the current action is in the sitemap, the call to .Menu() will render the correct <ul><li>.. data. However, if I got to a page that is not in the sitemap such as /Home/Login, then it will not render any html at all (not even a comment, just empty space). This isn't an [authorize] issue; the menu is fine when i'm in '/Home/Index'.
It seems like it should render what was requested, but just not set the IsCurrentNode and IsNodeInPath properties. Here is the call I am making
<div id="main-nav">
#Html.MvcSiteMap().Menu(0, true, true, 1)
</div>
The Mvc.sitemap file:
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Form New Human" controller="Person" action="Create"/>
<!-- there is no mvcSiteMapNode for "Home" "Login" -->
</mvcSiteMapNode>
Found the way around it. It apparently isn't a built in extension method, or at least I couldn't find one. You could call Html.MvcSitemap().Menu(Html.MvcSiteMap.Provider.RootNode,...) but I didn't want to instantiate the helper twice.
<div id="main-nav">
#{
var sm = Html.MvcSiteMap();
#sm.Menu(sm.Provider.RootNode, true, true, 2); // 2 levels (home, plus main nav)
}
</div>
Looking around in the disassembly seems to show that it works a little like this:
You really need a starting node
If you don't give it one, it tries to find one based on the current node
plus restrictions (forward searching, depth restrictions, etc)
if you want nodes from level 1, you have to know what level you are on
Since that returns null, starting node is null, which means the helper writes an empty string
There may be a combination of tricks, or an overload or two, which can be finagled into doing this, but I can't find it right now. This works for my needs (simple top menu). There has to be a simpler way to do this, something with wild cards, or route based, with a closest match thing going on. I figured menus were a fairly standard part of a web app, and this would be covered :)