Angular 4: Updating the view - html

I'm very new to web-development in general, but I'm trying to build my website and came across the following problem I haven't be able to solve. I'm using angular 4
I have a div highlighting some code in my html file:
<div *ngIf="step1Updated">
<prism-block
[code]="step1"
[language]="'python'">
</prism-block>
{{ step1 }}
</div>
In my typescript file:
step1Updated = false;
step1 = '';
onStep1(fileType: string) {
this.step1 = this.step1service.returnCode(this.language, fileType);
this.step1Updated = true;
}
Now on my html page, when I click from a selection of buttons executing onStep1() with different content, the content within my string interpolation changes, the {{ step1 }}, but the content within my prism-block doesn't. I can see that this is because we need two-way databinding but I've tried to put the [(ngModel)]="step1" two way data binding in the prism-block, div, etc... hoping that it would catch the update and then update the block, same as putting code in [(code)] but all resulted in errors..
any help or advice would be really appreciated!

here you need to load PrismComponent dynamically to update its view.refer my plunker(http://plnkr.co/edit/tEgnnS) code.
onStep1(fileType: string) {
const crf = this.cfR.resolveComponentFactory(PrismComponent);
this.cc.clear();
const cf = this.cc.createComponent(crf);
(<PrismComponent>cf.instance).code = this.step1service.returnCode(this.language, fileType);
}

Related

How can I use Render sub-template in a C# template in a Content module that uses lists within lists?

2SXC 10.25.2 / DNN 9.3.2
I have a 2sxc module that uses a C# template with "list" enabled. I have a content type called "pathway" and inside that I have 2 entity picker fields for "first step sessions" and then "next step sessions". These entity pickers use a "session" content type. Inside each of those "session" content types I also have an entity picker for "speaker(s)". All in all, it's a setup that I have lists within lists within lists.
When I create the loops for each of the sublists, I can easily do that within the 1 C# template but it becomes repetitive, long, and unruly because there's so much c# code where I'm looping the same session template for different entity picker sections. So, I tried using the "Render sub-template" code to simplify the template - I created new sub templates and inserted them in - it seemed to work at first, however, the template started outputting all "session" items into each item in the list.
I suspect that the subtemplate somehow loses the context of the item that it's in so it's outputting everything. Is there something special I need to know about using subtemplates with for each loops? Do I have to include params and, if so, how do I do that?
EDIT to include code sample:
Here is a small, simplified version of the code I'm working with:
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
<div class="lead-sessions text-green">
#foreach(var item in AsList(Content.LeadSessions as object)){
<h4>#item.LeadSessionTitle</h4>
<p>#item.LeadSessionText</p>
}
</div>
<h3>Next Sessions</h3>
<div class="next-sessions text-green">
#foreach(var nextitem in AsList(Content.NextSessions as object)){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
}
I want to make a subtemplate so I don't have to repeat the same code for the sessions loop. How could I simplify this template to use a subtemplate for looping the sessions within the lead-sessions and next-sessions?
So based on the modified question, it's a bit like this
#foreach(var Content in AsList(Data)) {
<h2>#Content.Title</h2>
<h3>Lead Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.LeadSessions })
<h3>Next Sessions</h3>
#RenderPage("_inner.cshtml", new { Items = Content.NextSessions })
}
Second file _inner.cshtml
#{
var items = AsList(PageData["Items"]);
}
<div class="next-sessions text-green">
#foreach(var nextitem in items){
<h4>#nextitem.LeadSessionTitle</h4>
<p>#nextitem.LeadSessionText</p>
}
</div>
Yep, you can just use RenderPage without params, or pass in params like in the blog app:
#RenderPage("shared/_Category Filter.cshtml", new { MobileView = true, FilteredCategory = filteredCategory })
See https://github.com/2sic/app-blog/blob/master/_List.cshtml#L25
Then the template can retrieve the values like
#{
var filteredCategory = PageData["FilteredCategory"];
}
See https://github.com/2sic/app-blog/blob/master/shared/_Category%20Filter.cshtml#L6
You can pass around any amount of values/objects like this.
You can also create helpers - and then call those helpers. Like this
https://github.com/2sic/app-news/blob/master/shared/_Helpers.cshtml#L24-L33

How can I display dynamic HTML having Vue variables inside?

I am trying to make the page content dynamic. I am using ck-editor in which i added html content and used the same vue variables inside it which i declared in the vue file where i want to show ck-editor data. I found a similar post vuejs - “editing” html inside variable
which works fine if i write the html inside a variable. But in my case, i am saving data in database. It is saving properly with html tags, without converting the tags. When i get data using axios it returns it in form of string. And i used vue variable to display that html.
Here is my code for better understanding:
<div v-html="htmlText"></div>
new Vue({
el: '#app',
created() {
this.getSalesContent();
},
data: {
salesContent: '',
pageName: 'Sales',
salesNumber: '987-586-4511'
},
computed: {
htmlText() {
return `${this.salesContent}`;
//return this.salesContent;
}
},
methods: {
getSalesContent(){
axios.get('api/Sales').then(({ data }) => { // getting data from DB
this.salesContent = data.sales; //data.sales have this.pageName and this.salesNumber variables
});
}
}
});
Here is the example of data saved in db:
<p style="font-weight:bold"><span style="color:red">{{pageName}}</span>,</p>
<p style="font-weight:bold"><span style="color:red">${this.pageName} ${this.pageName}</span></p>
<p style="font-weight:bold">Contact Sales at ${this.salesNumber} {{salesNumber}}</span></p>
I used variables in all possible ways. But on the page they are printing in it the same way i saved it. Here is the output:
screenshot
Can anyone help me make it working.
Thanks in Advance.
According to the docs this does not seem possible:
https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Particularly:
The contents of the span will be replaced with the value of the
rawHtml property, interpreted as plain HTML - data bindings are
ignored.
You could as suggested in that answer just use a computed based on what you get from the server.
IMHO since the salesContent is fetched from db, it's a plain String. Thus nor vuejs or vanilla javascript will replace the inline variables with their values. (It may be possible by using eval, but it's totally out of question...) You should manually do that with String replace function. Like the following:
<p style="font-weight:bold"><span style="color:red">{{pageName}}</span>,</p>
<p style="font-weight:bold">Contact Sales at {{salesNumber}}</span></p>
methods: {
getSalesContent(){
axios.get('api/Sales').then(({ data }) => { // getting data from DB
let salesContent = data.sales; //data.sales have this.pageName and this.salesNumber variables
salesContent = salesContent.replace(/{{pageName}}/g, this.pageName)
salesContent = salesContent.replace(/{{salesNumber}}/g, this.salesNumber)
this.salesContent = salesContent
});
}
}

*ngIf or [hidden] not working correctly

I'm trying to allow for hiding of certain sections of the project I'm working on via user toggle. It saves in the database and gets pulled when the page is loaded in the constructor using the following code
this.http.get(`api/section/get/${this.id}`, this.id).subscribe(res => {
this.section = res.json()[0];
this.sect = res.json();
console.log(this.section);
this.hideIntro = this.sect[0].hideIntro;
this.hideMainVideo = this.sect[0].hideMainVideo;
this.hideHandout = this.sect[0].hideHandout;
this.hideQuiz = this.sect[0].hideQuiz;
console.log("Hide Intro = " + this.hideIntro);
console.log("Hide Main = " + this.hideMainVideo);
console.log("Hide Handout = " + this.hideHandout);
console.log("Hide Quiz = " + this.hideQuiz);
});
The HTML is as follows...
<div class="row classMainBackground col-md-12" *ngIf="!hideIntro">
...content...
</div>
For some reason, no matter what I do, whether I change it to *ngIf="hideIntro == false" or even use [hidden]="hideIntro", it is not working.
Even the console logs in the .ts file show up correctly. Is there a reason why this is not working for me? I've used it in other positions and it works fine there...
Does it have something to do with assigning it in the constructor or something?
Thanks in advance!
Angular change detection runs in response to use interaction with the component. If values are updated outside of that event handling (such as after an HTTP request), you need to manually tell the component that it has changed.
constructor(private changeDetector: ChangeDetectorRef){}
this.http.get(`api/section/get/${this.id}`, this.id).subscribe(res => {
[...]
this.changeDetector.markForCheck();
})
More in depth reading: https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html
I ended up solving the problem by using {{!section.hideIntro}} in the HTML instead of trying to define a new variable to pass that boolean to.
I believe the answer was a combination of what #Vlad274 and #ConnorsFan were mentioning.
the HTML was returning an [object object] for {{hideIntro}} and it seems like there's a delay between the assigning the new value data from the GET response before the DOM actually loads.
Grabbing the data right from the GET respone variable ended up doing the trick.

Error on looping through a RelatedLinks property of dynamic Node in Razor

I have a Razor partial which displays my site navigation:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
var home = CurrentPage.Site();
umbraco.NodeFactory.Node navigationSettingsNode = MySite.Umbraco.NavigationSettings;
dynamic navigationSettings = new umbraco.MacroEngines.DynamicNode(navigationSettingsNode.Id);
var settings = home.Children.Where("DocumentTypeAlias == \"Settings\"").First();
}
#if (navigationSettings.HasValue("topNavigation"))
{
<ul>
dynamic topNavigation = navigationSettings.topNavigation;
var topNavigation2 = settings.topNavigation;
<span>#topNavigation</span>
<span>#topNavigation2</span>
foreach(dynamic item in topNavigation)
{
<li>
#item.caption
</li>
}
</ul>
}
Initially I was looping through topNavigation2 items which worked fine and with no problem.
Now I'm looping through topNavigation items and it throws an error:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'char' does not contain a definition for 'link'
I don't want to use var settings anymore, I want to use only dynamic navigationSettings variable. In order to get the right node of navigationSettings I need to some operation and I don't fancy to paste the same code in every view I want to use it so I want it to be accessible from dll and available to use anywhere.
Also the navigationSettings node in my Umbraco is outside of main content tree so is not a child of Home.
Why isn't it working? Both
dynamic topNavigation = navigationSettings.topNavigation;
var topNavigation2 = settings.topNavigation;
produce the same json result and both are dynamic objects.
How to make it work correctly?
I'm using MVC 5.2.3
It looks like your topNavigation property is a string, and so when you call for each on it, it's iterating through the characters in the string.
Also, don't use NodeFactory, it's deprecated. You should be using IPublishedContent instead.
I'd use the strongly typed content objects instead of dynamic, as a) they're faster, and b) they're easier to work with.
Here's a great article explaining the different ways of getting content: https://24days.in/umbraco-cms/2015/strongly-typed-vs-dynamic-content-access/

Show different default page depending on stored value

I am trying to make an windows store app where the default page (first page that comes up when app loads) changes depending on stored value.
I have following files
- js
|- default.js
- default.html
- page_A.html
- page_B.html
default.js has the following code:
if (localStorage["value"] == undefined || localStorage["value"] == "pageA") {
localStorage["value"] = "pageA";
//WinJS.Navigation.navigate("page_A.html");
window.location.assign = "page_A.html";
} else {
localStorage["value"] = "pageB";
//WinJS.Navigation.navigate("page_B.html");
window.location.assign = "page_B.html";
}
WinJS.Navigation code does not work at all. So I tried using window.location and what's happening is instead of loading the actual page, it loads an empty page as shown below.
I tried using both href and assign for windows.location object. What's interesting is that it seems like href and assign loads the page because if I have page_A/B.js associated with pageA/B.html and have a simple console.log statement, then the log statement does get logged, but it does not render the page.
Any ideas? I've been stuck for a while.
Try putting your default.js at the root of your project, next to page_A.html and page_B.html, or, and I don't know if this works, you can try calling those pages with ..\page_X.html.
Also, you can add an error handler function to your navigate in case there's something else going on that you're not seeing.
WinJS.Navigation.navigate('page_A.html', {}).then(function () {
// it worked!
}, function (err){
// something went wrong
});