I have a little problem. I have some products in shop ( I don't know how many products there will be ). In the main site I would like to print only 3 products in one row. And I don't know how to do loop to work this. Now in my code I have only one row and I doesn't look nice. I designed my row t contain only 3 products.
<div class="row-fluid">
<ul class="thumbnails">
#if (count($subcategoryProducts)==0)
There's no products
#else
#foreach($subcategoryProducts as $product)
<li class="span4">
<div class="thumbnail">
<a class="zoomTool" href="/product/{{$product->id}}" title="add to cart"><span
class="icon-search"></span> Details</a>
<a href="/product/{{$product->id}}"><img src="{{$product->getImageURL()}}"
alt=""></a>
<div class="caption cntr">
<p>{{$product->name}}</p>
<p><strong> {{$product->price}}</strong></p>
<h4><a class="shopBtn" href="#/{{$product->id}}" title="add to cart"> Add to cart </a>
</h4>
<br class="clr">
</div>
</div>
</li>
#endforeach
#endif
</ul>
</div>
Where's my mistake? Shoul I put this loop in another maybe?
Approach 2 here by JERRIE PELSER was the answer to my prayers today.
Use a simple extension method
public static class ArrayExtensions
{
/// <summary>
/// Splits an array into several smaller arrays.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
/// <param name="array">The array to split.</param>
/// <param name="size">The size of the smaller arrays.</param>
/// <returns>An array containing smaller arrays.</returns>
public static IEnumerable<IEnumerable<T>> Split<T>(this T[] array, int size)
{
for (var i = 0; i < (float)array.Length / size; i++)
{
yield return array.Skip(i * size).Take(size);
}
}
}
Use the extension method in foreach to split the rows by the number of columns required
#model IEnumerable<BootstrapGridLayout.Models.Article>
#using BootstrapGridLayout;
#{
ViewBag.Title = "Home Page";
}
#foreach (var row in Model.ToArray().Split(3))
{
<div class="row">
#foreach (var article in row)
{
<div class="col-md-4">
<div class="thumbnail">
<img src="#article.Thumbnail" data-holder-rendered="true" style="height: 200px; width: 100%; display: block;">
<div class="caption">
<h3 id="thumbnail-label">#article.Name</h3>
<p>#article.Description</p>
</div>
</div>
</div>
}
</div>
}
Related
I would like to use razor template I use vs19 on windows
no option for creating a new
RazorTemplatePreprocessor
so, in the shared project I created an empty text file and change extension to .cshtml and change file custom tool from property to
RazorTemplatePreprocessor
which generated the corresponding cs file
in cshtml file
#using DataBase.Models;
#model List<Brand>
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div class="container">
<div class="columns">
#foreach (var m in Model)
{
<div class="one-fifth column">
<span class="d-inline-block p-3 bg-red text-white">
#m.ModelName
</span>
</div>
<div class="four-fifths column">
<span class="d-inline-block p-3 bg-green">
#m.ModelDescription
</span>
</div>
}
</div>
</div>
</body>
</html>
but in loop there are an error for Model (var m in Model)
The name 'Model' does not exist in the current context
Try to change (It's better to pass your Model class)
#foreach (var m in Model)
to
#foreach (var m in #Model)
The #model directive should be followed by a Type,this could be any custom class.
When #Model is referenced throughout the template, it provides a reference to the object passed to the template when it is generated.
Update:
for example,your model class like:
public class YourModel{
...
public List<Brand> Brands{ get; set; }
public class Brand{
public strin ModelName{ get; set; }
public strin ModelDescription{ get; set; }
}
}
then
#using DataBase.Models;
#model YourModel
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div class="container">
<div class="columns">
#foreach (var m in #Model.Brands)
{
<div class="one-fifth column">
<span class="d-inline-block p-3 bg-red text-white">
#m.ModelName
</span>
</div>
<div class="four-fifths column">
<span class="d-inline-block p-3 bg-green">
#m.ModelDescription
</span>
</div>
}
</div>
</div>
</body>
</html>
So I kept sketching out algorithms to see how this would work. Kept hitting my head on the keyboard because frankly, nothing seems to work. Basically the hardcoded HTML looks like this:
<div class="row">
<div class="column">
<a href="products.html#drinks"><div id="drinks">
<h2>Drinks</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#preppedfood"><div id="preppedfood">
<h2>Prepped Food</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#coffee"><div id="coffee">
<h2>Coffee Machines</h2>
</div></a>
</div>
<div class="column">
<a href="products.html#snacks"><div id="snacks">
<h2>Snacks</h2>
</div></a>
</div>
</div>
<div class="row">
<div class="column">
<a href="products.html#nuts"><div id="nuts">
<h2>Nuts of All Kinds</h2>
</div></a>
</div>...till the last div class="row" and it's column divs
So the HTML works fine, here's a screenshot:
This is how I want it to look!
But using VueJS so that I can "DRY out" my markup, I'm using the v-for directive like this in the Prods.vue component. Here's the template markup:
<div class="row" v-for="(data, index) in images" v-bind:key="data" v-if="data.ImageId%4 == 0">
<h1>{{index}}</h1>
<div
class="column"
v-for="data in images"
v-bind:key="data"
v-if="computedIndex(index) *4 >= index && index < (computedIndex(index)+1) / 4"
v-lazy-container="{ selector: 'data' }"
>
<a :href="'products/#'+data.Name">
<h4>{{data.H2}}</h4>
<img :src="'../../../static/products/'+data.Name+'.png'" :alt="data.Name+'.png'" />
</a>
</div>
</div>
And the script:
<script>
import Prods from '../../../other/jsons/products.json'
import VueLazyload from 'vue-lazyload'
export default {
data() {
return {images: Prods}
},
methods: {
computedIndex(index) {
return Math.trunc(index/4)
}
}
}
//v-for in row
//v-for in column
</script>
And this is what shows up instead:
enter image description here
Instead of juggling with indices, it seems more straightforward to me to compute the shape of your array to suit your DOM:
computed:
imageRows () {
return this.images.reduce((acc, n, i) => {
i % 4 ? acc[acc.length - 1].push(n) : acc.push([n])
return acc
}, [])
}
To be used something like this:
<table>
<tr v-for="(imageRow, i) in imageRows" :key="i">
<td v-for="image in imageRow" :key="image">
<foo/>
</td>
</tr>
</table>
(Your data seems tabular to me, so I'm showing this example as a <table>, but you can substitute that with <div>'s if you prefer, of course.)
I'm trying to create rows dynamically with razor but I can't figure out how to wrap this around. What I want is for every 5:e object in my model I want to create a new row/div <div class="row pics_in_a_row"> so that each row contains five or less images.
<section class="slice">
<div class="wp-section">
<div class="container">
<div class="row pics_in_a_row">
#{
int i = 0;
foreach (dbphoto.Models.Image s in Model.images.OrderByDescending(x => x.idimage))
{
if (i % 5 == 0 && i != 0)
{
<br />
}
i++;
if (1 == 1)
{
<div class="flxbox" style="flex: calc(1024/713)">
<a href="#s.HighResolution" data-fancybox="gallery" data-caption="xyz, Stockholm">
<img src="#s.LowResolution" class="img-fluid rounded flximg" />
</a>
</div>
}
}
}
</div>
</div>
</div>
</section>
Bonus question: how can I get the height and width of the image and add it to the calc() css?
You should add the div with class row pics_in_a_row inside your loop
This should create a a row for every 5 items (or less for the last row when the remaining items are less than 5).
<div class="container">
#{
var numberOfColsNeeded = 5;
var totalCounter = Model.images.Count();
var itemCounter = 1;
}
#foreach (var item in Model.images)
{
if (itemCounter % numberOfColsNeeded == 1)
{
#:<div class="row pics_in_a_row">
}
<div class="flxbox" style="flex: calc(1024 / 713)">
<img src="#item.LowResolution" class="img-fluid rounded flximg" />
</div>
if ((itemCounter % numberOfColsNeeded == 0) || ((itemCounter) == totalCounter))
{
#:</div>
}
itemCounter++;
}
</div>
I have a json with some objects. Using #foreach from Razor, I want to expose the results on a template, along with some filters that will filter my results.
The problem is that I can't render the template correctly. I want my sidebar/widget to be rendered one time one the right, and the results to be rendered one bellow another, and to look as you'd expect.
CODE:
#{int i = 0;}
#{
var client = new WebClient();
var json = client.DownloadString("http://example.com/raw/a5N8mJ2Y");
var results = Json.Decode(json);
}
<div class="container">
<div class="row">
#foreach (var result in results)
{
i++;
if (i == 2)
{
<!-- Left sidebar goes here -->
<aside id="sidebar" class="col-sm-3">
<section id="filters">
<h3>Filtre</h3>
...
</section>
</aside>
}
<div style="border-style: groove; " class="col-sm-9">
<!-- objects from json go here -->
</div>
}
</div>
</div>
Screenshot:
If you want your sidebar to appear only once, it's pointless being in the foreach loop. It's getting put to the right and pushing the next item down because you're placing it between the results columns.
I think you should set it out so there is one aside element outside of the foreach loop and one column that contains the json items, e.g.
<div class="container">
<div class="row">
<!-- Left sidebar goes here -->
<aside id="sidebar" class="col-sm-3">
<section id="filters">
<h3>Filtre</h3>
...
</section>
</aside>
<div class="col-sm-9">
#foreach (var result in results)
{
<div class="item-result">
<!-- object result here -->
</div>
}
</div>
</div>
</div>
Then just style your .item-result class like:
.item-result{
border-style: groove;
display: block;
margin-bottom: 15px;
}
I'm trying to view notifications on razor view. I used foreach loop to get the data from the model.I want to display both "invitations" and "Requests" divs on the view like in the two table columns.One invitation down after another invitation.one request down after another request..(in one column all the invitations and requests on the other).. i used css float to do this.. but in the divs get mix in the result..why is that? there are some othaer elements in the view like, nav bar,side bar etc...my code is as follows;
foreach (var item in Model)
{
if (#item.CreatedBy == item.UserId)
{
<div style="float: right; width: 580px;">
<div class="panel panel-info" style="width:500px;margin-right:50px">
×
<div class=" panel-heading">
<h3 class="panel-title">Notification #counter1</h3>
</div>
<div class="panel-body">
<p>Event is created by yourself .Budget of the event is #item.Budget <p>
#if (item.IsAccepted)
{
<p>You have accept the invitation!!!</p>
}
#if (!item.IsAccepted)
{
<p>You haven't accept the invitation yet!!!!</p>
}
#{counter1++;}
</div>
</div>
<br />
</div>
}
else
{
<div style="width: 580px; float: left">
<div class="panel panel-info" style="width:500px;margin-left:250px;">
×
<div class=" panel-heading">
<h3 class="panel-title">Notification #counter2</h3>
</div>
<div class="panel-body">
<p>Event is created by #item.Email .Budget of the event is #item.Budget <p>
#if (item.IsAccepted)
{
<p>You have accept the invitation!!!</p>
}
#if (!item.IsAccepted)
{
<p>You haven't accept the invitation yet!!!!</p>
}
#{counter2++;}
</div>
</div>
<br />
</div>
}
}
What you need is css attributes "clear: right" and "clear: left" for your div's.
However, once you use them you will find next problem - there will be vertical gaps between your div's on the right and left side. That is because you are placing new div's right into body element of html page in your foreach loop. To make it right, you should first create two containers (divs) to which you should respectively add your divs containing data.
Unfortunately, with your current implementation you would have to iterate over your Model twice - once to fill up the right container with divs, and then once again to fill up the left container.
A better approach would be to create a ViewModel containing two collectios of objects which you are currently using, e.g.:
public class MyViewModel
{
public IList<MyModel> Invitations { get; set; }
public IList<MyModel> Requests { get; set; }
}
and use it as your View's model
#model MyApplication.Models.MyViewModel.
With this approach, you also remove some logic from the view, which is a good thing.
Here is an updated code for your view using the ViewModel as View's model:
#model MvcApplication1.Controllers.MyViewModel
#{
int counter1 = 0, counter2 = 0;
}
<div style="float: right; width: 580px; clear:right">
<span>Invitations</span>
#foreach (var item in #Model.Invitations)
{
if (#item.CreatedBy == item.UserId)
{
<div>
<div class="panel panel-info">
×
<div class=" panel-heading">
<h3 class="panel-title">Notification #counter1</h3>
</div>
<div class="panel-body">
<p>Event is created by yourself .Budget of the event is #item.Budget <p>
#if (item.IsAccepted)
{
<p>You have accept the invitation!!!</p>
}
else
{
<p>You haven't accept the invitation yet!!!!</p>
}
#{counter1++;}
</div>
</div>
<br />
</div>
}
}
</div>
<div style="float: left; width: 580px; clear:left">
<span>Requests</span>
#foreach (var item in #Model.Requests)
{
<div>
<div class="panel panel-info">
×
<div class=" panel-heading">
<h3 class="panel-title">Notification #counter2</h3>
</div>
<div class="panel-body">
<p>Event is created by #item.Email .Budget of the event is #item.Budget <p>
#if (item.IsAccepted)
{
<p>You have accept the invitation!!!</p>
}
else
{
<p>You haven't accept the invitation yet!!!!</p>
}
#{counter2++;}
</div>
</div>
<br />
</div>
}
</div>
Good luck :)
Edit: a quick lookup to how the page looks after using provided solution:
https://jsfiddle.net/nh8Ls531/