HTML.DisplayFor method using string - asp.net

In my ASP.Net MVC appication I have a loop which i'd like to display different Properties values in HTML using the HTML.DisplayFor method. But it will not accept a string value to direct to the Model parameter.
Normal mode:
<img src="#Html.DisplayFor(model => model.Image_1)" />
My loop:
#for (int i = 1; i < 11; i++)
{
string currentImage = "Model.Image_" + i;
if ((#Html.DisplayFor(model => "Model.Image_" + i ).ToString()) != "")
{
<div>
<img src="#Html.DisplayFor(model => currentImage)" />
</div>
}
}
My results in the img src are just currentImage.
I'd like it to be Model.Image_" + i.
How would I do that?
If you have a better way of doing this that would be appreciated as well.
Should my images have their own Model -class, you think?

You can get the value of a property dynamically using reflection like this.
#for (int i = 1; i < 11; i++)
{
string imagePropName= "Image_" + i;
string imageSrc = Model.GetType().GetProperty(imagePropName).GetValue(Model) as string;
if (!string.IsNullOrEmpty(imageSrc))
{
<div>
<img src="#Url.Content(imageSrc)" />
</div>
}
}
Another alternative would be to write <img src="#Url.Content(Model.Image_1), <img src="#Url.Content(Model.Image_2) /> 10 times. I mean if you have created 10 properties, might as well be consistent with the implementation.
But as stephen said, just get a List of ImagePaths and loop through them in your View. If the requirement changes to displaying 20 images, you'd have to add 10 more properties.

Related

Making a button that shows or hides multiple images in a random location

I have a problem when I am making the website for one gallery.
I made the code for the button that can show and hide multiple images.
I intend to make the button can place several images in randomly.
I write the code that can function for only one image.
Please tell me the code that functions as a button to place multiple images in a random location.
Users can hide images by pressing the button.
And when users press the button again, it places the images in another random location.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const box = document.getElementById("color");
btn.addEventListener("click", () => {
let randY = Math.floor((Math.random() * height) + 1);
let randX = Math.floor((Math.random() * width) + 1);
box.style.top = randY + "px";
box.style.right = randX + "px";
});
function showhide() {
var x = document.querySelectorAll("#color");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
You're doing the correct thing in showHide() when using querySelectorAll. You are then able to get all images.
You should never have elements with the same ids. They should be unique. So querySelectorAll("#color") works, but it's now how you should do. Do a querySelector on "img.random" instead.
getElementById only returns a single element, not like querySelectorAll. So you need to use querySelectorAll('img.random').
This might be beyond your knowledge, I don't think you should add the images in HTML, but in javascript code.
a) Add all image paths in an array: ['https://image.com/image.png', ...]
b) Add a single img element. <img id="template" class="random">
c) In javascript code, clone that element for each image path in the array. You can use cloneNode for this.
d) Randomize each position for each element, just like you have done now.
e) Add each element to the DOM through appendChild. Have a unique div that you append to. Be sure to clear it every time second time you hit the button.
f) Solve all bugs along the way. :P
The problem
The main issue here is that you're using getElementById to query #color
const box = document.getElementById("color");
Since getElementById only returns one element (but you have two in your DOM) and the style only applies to one element. That's why you're seeing only one element is randomly moving and the other just stay in the same place.
A side note here, id should be unique in a DOM.
You're in fact using the correct API for the job in the showhide function
var x = document.querySelectorAll("#color");
The fix:
To fix this, you need to query all images by their classname (as suggested in the side note, don't use id for the job)
const boxes = document.querySelectorAll(".random");
Now we have a node list, as you do in the showhide function, we need to loop thru it, I'm not using a for loop here, instead, a forEach loop, it's just more terser and a modern addition to the JS
// Since boxes are not array, we need to covert it to array so we can use that handy `.forEach` here:
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
Now, this should fix your issue. See the complete code below.
const btn = document.querySelector("button");
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
const boxes = document.querySelectorAll(".random");
btn.addEventListener("click", () => {
Array.from(boxes).forEach(box => {
box.style.top = Math.floor((Math.random() * height) + 1) + "px";
box.style.right = Math.floor((Math.random() * width) + 1) + "px";
})
});
function showhide() {
var x = document.querySelectorAll(".random");
var i;
for (i = 0; i < x.length; i++) {
if (x[i].style.display === "block") {
x[i].style.display = "none";
} else {
x[i].style.display =
"block";
}
}
}
body {
height: 500px;
}
.random {
position: absolute;
}
<button onclick="showhide()" value="Zeige Features" id="button">click me</button>
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/200/200/">
<img id="color" style="display: none;" class="random" src="http://lorempixel.com/100/100/">

How to add different css class dynamically in a loop every 3 times

Basically what i need to do is looping all the posts and add css to article class like "cb-no-1" and the second one "cb-no-2" and the third one "cb-no-3" and repait it again until there's no post.
#foreach (var post in Model.Posts)
{
//First iteration
<article class= "cb-no-1">
</article>
//Second iteration
<article class= "cb-no-2">
</article>
//Third iteration
<article class= "cb-no-3">
</article>
//Fourth iteration
<article class= "cb-no-1">
</article>
//and so on.
}
How to achive it. Thanks in advance.
Use a variable and increment that in the loop and use this variable name to build the class name. When the variable reaches 3 (or your limit), reset it to initial value.
#{
var counter = 0;
}
#foreach (var post in Model.Posts)
{
if (counter >= 3)
{
counter = 0;
}
<article class= "cb-no-#(++counter)">#post.Title</article>
}
use a variable like as i inside the loop which is inited from 1 and increases in each loop and when it reachs the 4, reset it to 1
then use it for class name
Shyju, the first responder, has the right idea, but there are two modifications you need to make to his answer.
First, his code gives you a variable from 0 to 2. you asked for 1 to 3,. so the initialization needs to be "var counter = 1" and the "if" test needs to be just greater than 3, not greater than or equal to 3. Or you could change the 3 to a 4, such as: if (counter >= 4).
The second item left off of that code snippet is something to increment the counter. I'm not sure which dialect or language you are writing in but something like:
Counter+=1
or
counter = counter + 1
Modified, that code snippet would look like:
var counter = 1;
#foreach (var post in Model.Posts)
{
if (counter >= 4)
{
counter = 0;
}
<article class= "cb-no-#(++counter)">#post.Title</article>
counter += 1
}
Again, I do not know which language you are writing in so check my syntax carefully.

Glass Mapper breaking standard values for image field

Consider the template:
Company
Logo (Image field)
Company Name (Text field)
The Company template has standard values set on both fields. If we get a Company item and save it using Glass without making any changes, the Logo field no longer uses the standard value. (The Company Name field is untouched.)
The issue, it seems, is that the Glass.Mapper.Sc.DataMappers.SitecoreFieldImageMapper serializes the value of that field differently than Sitecore does. When it tries to save, it thinks it's a change to the field and no longer uses the standard value.
Standard Value:
<image mediaid="{GUID}" />
Glass-generated Value:
<image height="64" width="64" mediaid="{GUID}" alt="Alt text" />
Is there a way to make Glass generate the same output as Sitecore?
I think that problem is in a way how SitecoreFieldImageMapper map ImageField to Image. For getting Height, Width and Alt are used public properties. If we look on them via reflector we will see that values of it get not directly from field:
public string Alt
{
get
{
string text = base.GetAttribute("alt");
if (text.Length == 0)
{
Item item = this.MediaItem;
if (item != null)
{
MediaItem mediaItem = item;
text = mediaItem.Alt;
if (text.Length == 0)
{
text = item["Alt"];
}
}
}
return text;
}
set
{
base.SetAttribute("alt", value);
}
}
If field does not contain value(e.g. for "alt": if (text.Length == 0)) then value will be received from MediaItem that is linked. It cause adding Height, Width and Alt from media library item after saving of field.
To fix this problem you could try replace this code:
int height = 0;
int.TryParse(field.Height, out height);
int width = 0;
int.TryParse(field.Width, out width);
img.Alt = field.Alt;
img.Height = height;
img.Width = width;
with direct getting attributes rather than usage of properties:
int height = 0;
if(int.TryParse(field.GetAttribute("height"), out height))
{
img.Height = height;
}
int width = 0;
if(int.TryParse(field.GetAttribute("width"), out width))
{
img.Width = width;
}
img.Alt = field.GetAttribute("alt");
With Alt property everything should be ok. But there could be problems with Width and Height as they are not Nullable and I am not sure how GlassMapper will handle Image with Width and Height that you haven't set.

How to manage positions of DisplayObjects in actionscript?

I use the following code to set position of a DisplayObject to center.
obj.x = (screen_width - obj.width) / 2;
or
obj.x = (parentObj.width - obj.width) / 2;
And I use the following code to show 2 objects vertically.
obj2.x = obj1.width + interval
And I use the following code to show 2 objects vertically and set the position of them to center.
var obj3:Sprite = new Sprite;
obj3.addChild(obj1);
obj3.addChild(obj2);
obj2.x = obj1.width + interval;
obj3.x (screen_width - obj3.width) / 2;
Are the above codes a good way to manage positions of DisplayObjects?
Are there better and simple ways to do that?
Well you can also add them into a HGroup or a VGroup, (or HBox and VBox if you are using Flex 3). But when I want to implement a vertical layout without using these kind of elaborate objects, I usually create a "update()" method (note that the following code may contain syntax errors : it is just provided as an algorithm example):
private function update():void
{
// The vertical gap between elements
var gap:int = 4;
// The cumuled height
var cumuledHeight:Number = 0;
// The number of elements
var n:int = numElements;
// The element at each loop
var o:IVisualElement;
for (var i:int = 0; i<n; i++) {
// Gets the element
o = getElementAt(i);
// Sets its vertical position
o.y = cumuledHeight + gap*i;
// Updates the cumuled height
cumuledHeight += o.height;
}
}
Yes, there is a simpler way by using Flex to center it with horizontalCenter=0 and verticalCenter=0.

Is there a web control to dynamically generate a table of contents?

Say I have a basic page like so:
<custom:TableOfContents />
<h1>Some Heading</h1>
<h2>Foo</h2>
<p>Lorem ipsum</p>
<h2>Bar</h2>
<p>Lorem ipsum</p>
<h2>Baz</h2>
<p>Lorem ipsum</p>
<h1>Another Heading</h2>
<h2>Qux</h2>
<p>Lorem ipsum</p>
<h2>Quux</h2>
<p>Lorem ipsum</p>
Assume all the header tags exist as server side controls. Is there some web control <custom:TableOfContents /> for ASP.NET webforms that will dynamically generate a table of contents that looks something like the following (when rendered to the screen):
1. Some Heading
1.1. Foo
1.2. Bar
1.3. Baz
2. Another Heading
2.1. Qux
2.2. Quux
Ideally, each entry in the table of contents would be a hyperlink to a dynamically generated anchor at the appropriate place on the page. Also, it would be nice if the text of each header tag could be prefixed with its section number.
If not a web control, is there some easier way of doing this? Keep in mind that many of the header tags are going to be created by data bound controls, so manually maintaining the table of contents is not an option. It seems like the webforms model is ideally suited to creating such a control, which is why I'm surprised I haven't yet found one.
I needed to do a similar thing a few days ago and, though not a webcontrol, used jQuery.
$(document).ready(buildTableOfContents);
function buildTableOfContents() {
var headers = $('#content').find('h1,h2,h3,h4,h5,h6');
var root, list;
var previousLevel = 1;
var depths = [0, 0, 0, 0, 0, 0];
root = list = $('<ol />');
for (var i = 0; i < headers.length; i++) {
var header = headers.eq(i);
var level = parseInt(header.get(0).nodeName.substring(1));
if (previousLevel > level) {
// Move up the tree
for (var L = level; L < previousLevel; L++) {
list = list.parent().parent();
depths[L] = 0;
}
} else if (previousLevel < level) {
// A sub-item
for (var L = previousLevel; L < level; L++) {
var lastItem = list.children().last();
// Create an empty list item if we're skipping a level (e.g., h1 -> h3)
if (lastItem.length == 0)
lastItem = $('<li />').appendTo(list);
list = $('<ol />').appendTo(lastItem);
}
}
depths[level - 1]++;
// Grab the ID for the anchor
var id = header.attr('id');
if (id == '') {
// If there is no ID, make a random one
id = header.get(0).nodeName + '-' + Math.round(Math.random() * 1e10);
header.attr('id', id);
}
var sectionNumber = depths.slice(0, level).join('.');
list.append(
$('<li />').append(
$('<a />')
.text(sectionNumber + ' '+ header.text())
.attr('href', '#' + id)));
previousLevel = level;
}
$('#table-of-contents').append(root);
}
This will make an ordered list and append it to #table-of-contents with appropriate numbering (e.g., 1.1). Just a little bit of CSS is needed to hide the lists' built in numbering: #table-of-contents ol { list-style:none; }.

Resources