Unable to loop inside media Folder in Umbraco 8 - razor

I have 2 images in a media folder and I need to display them. I've been trying to loop inside the folder but have not been unable to.
That's my code:
var media = Model.Value<IEnumerable<IPublishedContent>>("mediaFolder");
foreach (var item in media){
<img src="#item.Url"/>
}
The result is a compilation error:
Exception Details: System.NullReferenceException: Object reference not
set to an instance of an object.

Assuming the property "mediaFolder" is a media picker that points to the folder, the code would need to be:
var media = Model.Value<IPublishedContent>("mediaFolder");
foreach (var item in media.Children()){
<img src="#item.Url"/>
}
The example code that you have above would only work if the "mediaFolder" was a multiple content picker that had picked the two files individually.

Related

how to get context of views in view container in angular

In the following example, https://stackblitz.com/edit/angular-s8udwh
I have created EmbeddedViews in the ViewContainer. When creating the views, I pass a context object and when deleting the views, I use the context to find index of the view and delete it from the view container. This works fine.
I have added a button which when clicked should print the info of views currently in the container. I can find the length and views in the container using the APIs of ViewContainer but how do I get the context object from the views?
This is the function I am unable to write
printViewInfo(){
//I want to get all the views which are currently in the container and print their context objects.
let length = this.vc.length
for(let i=0;i<length;i++){
let view = this.vc.get(i);
//how to get the context back here from view??
}
}
What is the way to find context of views in a ViewContainer? I see that get returns a ViewRef and the ViewRef doesn't contain context. But ViewContainerRef doesn't provide APIs which return an EmbeddedViewRef
I got this working by typecasting the ViewRef into EmbeddedViewRef<any>. Is this the right way? My concern is that if a ViewContainerRef contains both EmbeddedView and ComponentView then how will I distinguish between them? Or would it be a wrong design to use both EmbeddedView and ComponentView in the same ViewContainer?
printViewInfo(){
//I want to get all the views which are currently in the container and print their context objects.
let length = this.vc.length
for(let i=0;i<length;i++){
let view = <EmbeddedViewRef<any>> this.vc.get(i);
//how to get the context back here from view??
console.log("view.context.option ",view.context.option.description);
}
}

How to access html element text in chrome devtools console

I have a page with a whole bunch of blackquote tags.
In dev console I am typing document.getElementsByTagName("blockquote") that giving me an array.
But if I do document.getElementsByTagName("blockquote").innerText document.getElementsByTagName("blockquote").innerHTML document.getElementsByTagName("blockquote").textContent
document.getElementsByTagName("blockquote").outerText document.getElementsByTagName("blockquote").outerHTML
All return undefined
However if I inspect elements of the array document.getElementsByTagName("blockquote") I can see all above properties in place.
How to access at least one of them (innerText, outerHTLM, innerText, outerHTML, textContent) ?
Or if you want to access any specific element you can use index in array
for (var i=0; i <document.getElementsByTagName("blockquote").length; i++ ){
var singleElement = document.getElementsByTagName("blockquote")[i];
console.log(singleElement.innerHTML);
}
You need to iterate the array in order to access those properties. Something like this will work for them:
var elements = document.getElementsByTagName("blockquote");
for (var prop in elements)
{
if(elements.hasOwnProperty(prop)) {
console.log(elements[prop].innerHTML);
}
}
You can also try the following commands:
var elements = document.getElementsByTagName("blockquote");.This will return the list of elements.To access the text of your required element at i index
elements[i].value.

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/

TVML Add items dynamically?

I have seen this question (Force view to reload tvml content on Apple TV/tvos) and the answer describes how you could remove things from the DOM but is there any way to add them?
I know about the standard appendChild on a NodeList but how would you create the proper element to be appended? That is, when you create a document in TVML it is a special XML syntax that is then parsed into a document. Is there a way to parse just a portion of a document so that you can then add it into, say a section within a shelf to dynamically add more items to the row after the document has been presented?
P.S. I've tried using Presenter.parser.parseFromString() with the xml for the new item but it is throwing a IKDOMException with that syntax.
There are many approaches you can take to accomplish adding items dynamically. An important thing to note is that Apple's sample code is NOT structured for dynamic data very well.
After you create a template, you can change the document in a variety of ways. You should have ownership of the document after the template is created. In the following example, the variable doc contains a Stack Template document I'd like to manipulate.
var shelves = doc.getElementsByTagName("shelf"); //get all the shelves
var shelfToAddTo = shelves.item(0); //choose the index for the shelf you want to add to.
var sectionToAdd = `<section>
<lockup>
<img src="pathToImg" width="100" height="100"/>
<title>Title Goes Here</title>
</lockup>
</section>`;
shelfToAddTo.insertAdjacentHTML('beforeend', sectionToAdd); //this will add the new section before the </shelf> tag.
This will add a new section and lockup to the first shelf in your document.
UPDATE:
You can use DataItem API to manage your data with prototypes.
You can’t bind JSON objects directly to a template, you have to turn them into DataItem objects. Retrieve the desired section element and create a new data item for the section. Create new data items from the JSON objects. The setPropertyPath method is used bind the new data items to the section data item. Listing 5-4 shows a modified parseJson function that takes the information from the Images.json file, turns them into data items, and binds them to the appropriate section.
Using the prototype element, you can create a single lockup that contains like objects. Inside of the lockup, you define the structure of the lockup. Listing 5-5 shows a lockup that displays the objects defined as artwork in the type element. The URL and title for each image are pulled from the JSON object.
<prototypes>
<lockup prototype="artwork">
<img binding="#src:{url};" width="200" height="300"/>
<title binding="textContent:{title};" />
</lockup>
</prototypes>
<section binding="items:{images};" />
The following iterate and populate your prototype code using items from section:
function parseJson(information) {
var results = JSON.parse(information);
let parsedTemplate = templateDocument()
navigationDocument.pushDocument(parsedTemplate)
let shelf = parsedTemplate.getElementsByTagName("shelf").item(0)
let section = shelf.getElementsByTagName("section").item(0)
//create an empty data item for the section
section.dataItem = new DataItem()
//create data items from objects
let newItems = results.map((result) => {
let objectItem = new DataItem(result.type, result.ID);
objectItem.url = result.url;
objectItem.title = result.title;
return objectItem;
});
//add the data items to the section's data item; 'images' relates to the binding name in the protoype where items:{images} is all of the newItems being added to the sections' data item;
section.dataItem.setPropertyPath("images", newItems)
}
Template:
<document>
<stackTemplate>
<banner>
<title>JSON Shelf</title>
</banner>
<collectionList>
<shelf>
<prototypes>
<lockup prototype="artwork">
<img binding="#src:{url};" width="200" height="300"/>
<title binding="textContent:{title};" />
</lockup>
</prototypes>
<section binding="items:{images};" />
</shelf>
</collectionList>
</stackTemplate>
</document>
Reference:
https://developer.apple.com/library/content/documentation/TVMLKitJS/Conceptual/TVMLProgrammingGuide/GeneratingContentForYourApp.html
Hope it helps you.

Dynamically display a list of xml hotspots (for krpano) based on json list

A bit of a newbie question for xml/krpano,
I have a list of json items that I want to be dynamically loaded into XML <hotspots>. I can loop through each item in JavaScript but I have no clue how to do the same loop in XML!
Check out this picture:
Imagine that each rectangle with an image is one item in a JSON list. Each rectangle you see is a <hotspot>. Right now these three hotspots are hardcoded into the XML file, but I want to dynamically load hotspots based on how many JSON list items exist.
Here is one hotspot. If my json list has 16 items, I would expect 16 hotspots
to be loaded.
<!--* video image thumbnail *-->
<hotspot name="start" distorted="true"
url="/panorama/%$panoId%/thumb.png"
ath="0" atv="0"
ox="0" oy="36"
vr_timeout="2000"
zorder="99"
scale="0.8"
onclick="changepano( loadscene(video_scene, null, MERGE|KEEPVIEW|KEEPMOVING, BLEND(1)); );"
alpha="0.0"
onloaded="if(vr_start_done === true, removehotspot(start); start_vr(); , tween(alpha,1); );"
/>
Your question is about dynamically generating hotspots in KRPano from a JSON list.
It is not really clear to me the way you wrote your question if you want to read the JSON from KRPano XML file (let's say FROM KRPano) or if you are expecting to use Javascript to ask KRPano to produce the hotspots.
These are two completly distinct ways of doing it :)
Because I'm lazy and I suppose you want to deal with JSON in JS, I go for this solution...
Loading a JSON file from Javascript
Your KRPano project should look like a core HTML file presenting Javascript to embed the KRPano plugin.
There, you can declare a script content in your HTML in which you will parse your JSON content and you ask KRPano to generate a hotspot. This method should be called when you are sure KRPano is ready, or get it called from KRPano when it is ready, using "onready" attribute.
myHotspotList.json content:
var myHotspotList = [
{
name: "myFirstHotspot",
atv: 15.0,
ath: 56.5686,
url: "myHotspotImage.jpg"
}
];
tour.html content:
<html>
...
<script url="myHotspotList.json'></script>
<script>
function generateHotspots() {
// First, we get the KRPano plugin
var myKRPano = document.getElementById('krpanoSWFObject');
// Now we parse the JSON object
for(var idx in myHotspotList) {
// Get the current Hotspot data
var currHotspot = myHotspotList[idx];
// Ask KRPano to create a hotspot with our current name
myKRPano.call("addhotspot('"+ currHotspot.name +"');");
// Now set various attributes to this hotspot
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].atv, "+currHotspot.atv+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].ath, "+currHotspot.ath+");");
myKRPano.call("set(hotpost['"+ currHotspot.name +"'].url, '"+currHotspot.url+"');");
}
}
</script>
...
// When you ask for pano creation, give your generation method as callback
embedpano({target:"krpanoDIV", onready:generateHotspots});
...
</html>
I hope this help and you got the trick with calling JSON object attributes and all.
Regards