I have created a simple Gallery html helper, its not pretty at the moment, as I cannot get it work with Razor. (I would have liked to use Action as I would have done with the webforms viewengine)
public static HelperResult Gallery<T>(this HtmlHelper html,
IEnumerable<T> items,
int itemsPerRow,
Action rowContainer,
Func<T, HelperResult> itemContainer,
Action endRowContainer)
{
if (items == null)
return new HelperResult(writer => { });
int itemCount = 1;
return new HelperResult(writer =>
{
rowContainer();
foreach (var item in items)
{
if (itemCount % itemsPerRow == 0)
{
endRowContainer();
rowContainer();
}
itemContainer(item).WriteTo(writer);
itemCount++;
}
endRowContainer();
});
}
this is the intened usage, but the rowContainer and endRowContainer are outputed at the top of the generated HTML
#Html.Gallery(
Model.Stores,
3,
()=> { Response.Write("<div class=\"portfolio_box_container\">"); },
#<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
,
() => { Response.Write("</div>"); })
What im i doing wrong?
if should print off something like:
<div class="portfolio_box_container">
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
</div>
<div class="portfolio_box_container">
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
<div class="portfolio_box" style="padding-right: 25px">
<img src="item.png" width="120" height="43" alt="" />
</div>
</div>
The problem is that you should use the "writer" parameter of the HelperResult action to write the output in your actions to. Now you use Response.Write that immediately writes to the HTTP response, while the HelperResult has its own writer that will be copied to the response afterward.
The easiest solution is if you use an Action<TextWriter> instead of Action, and then you can pass on the "writer" to your action parts.
E.g. use a parameter Action<TextWriter> rowContainer, and call it as rowContainer(writer) in the Gallery helper.
Then you can pass such an action parameter like (writer)=> { writer.Write("<div class=\"portfolio_box_container\">"); }
Related
I am new to tailwind, so I apologize for this question ahead of time. I am trying to convert existing CSS animations into tailwind. Specifically, how can I create an infinite scroll through a list of items using tailwind? I found this youtube video which accomplishes the exact behavior I would like. If possible how can this be implemented using Tailwind. I tried to search for something along the lines of "infinite scroll" or "carousel" but I couldn't find any other examples except for this video.
I initially struggled with the video instructions. The video instructs to provide a flex box with a width of 200%. Tailwind's config allows me to extend the width in specific pixels; however, I was unable to get it working with percentages.
After some time I found this website which shows a method that only requires extending configure the keyframes and animation like so.
/** #type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
keyframes: {
marquee: {
'0%': { transform: 'translateX(0%)' },
'100%': { transform: 'translateX(-100%)' },
},
marquee2: {
'0%': { transform: 'translateX(100%)' },
'100%': { transform: 'translateX(0%)' },
},
},
animation : {
'spin-slow-30': 'spin 30s linear infinite',
'spin-slow-25': 'spin 25s linear infinite',
'spin-slow-10': 'spin 10s linear infinite',
'marquee-infinite' : 'marquee 25s linear infinite',
},
},
},
plugins: [],
}
Once set I am then able to define a new component in react. Given the layout of the items, two rows are needed to expand across the width of the screen. I've repeated these items several items per row to achieve 2x the width of the screen otherwise the marquee illusion will break as there isnt enough items to traverse the entire screen.
import React from 'react'
import item1 from '../assets/carousel/1.png'
import item2 from '../assets/carousel/2.png'
import item3 from '../assets/carousel/3.png'
import item4 from '../assets/carousel/4.png'
import item5 from '../assets/carousel/5.png'
const ScrollCarousel = () => {
return (
<>
<div className='mb-96'>
<div className="relative w-full p-16 overflowx-hidden">
<div className="flex absolute left-0 animate-marquee-infinite">
<div className='flex w-96 justify-around'>
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
</div>
<div className='flex w-96 justify-around'>
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
<img src={item1} alt="" />
<img src={item2} alt="" />
<img src={item3} alt="" />
<img src={item4} alt="" />
<img src={item5} alt="" />
</div>
</div>
</div>
</div>
</>
)
}
export default ScrollCarousel
there is a div with tag that by click on small image I change the src attribute and show it's the original size, but I don't know how to do in Alpine js?
<div>
<img id="main" />
</div>
/* small images from db */
<div>
foreach($images as $image){
<img id='small' src="images/.$image" />
}
</div>
in jquery :
$("#small").each(function(){
$(this).click(function(){
$("#main").attr('src', $(this).attr('src');)
})
})
})
but I don't know how to do in Alpine js?!
Something like this (using Laravel Blade syntax)?
<div x-data="{imageUrl: ''}">
<section>
<img id="main" :src="imageUrl" />
</section>
<hr />
<div>
#foreach($images as $image)
<img id='small' src="{{ images/.$image }}" #click="imageUrl = '{{ images/.$image }}'" />
#endforeach
</div>
</div>
Demonstrated in a pen here with some dummy data.
Check this codepen: Image Preview Demo. Hope this helps.
<div class="flex items-center justify-center text-gray-500 bg-blue-800 h-screen">
<div class="w-full">
<h3 class="mb-8 text-xl text-center text-white">Image Preview Demo</h3>
<div class="w-full max-w-2xl p-8 mx-auto bg-white rounded-lg">
<div class="" x-data="imageData()">
<div x-show="previewUrl == ''">
<p class="text-center uppercase text-bold">
<label for="thumbnail" class="cursor-pointer">
Upload a file
</label>
<input type="file" name="thumbnail" id="thumbnail" class="hidden" #change="updatePreview()">
</p>
</div>
<div x-show="previewUrl !== ''">
<img :src="previewUrl" alt="" class="rounded">
<div class="">
<button type="button" class="" #click="clearPreview()">change</button>
</div>
</div>
</div>
</div>
<div class="mt-2 text-center text-white">
<a class="w-32 mx-2" href="https://tailwindcss.com/">TailwindCSS</a>
<a class="w-32 mx-2" href="https://github.com/alpinejs/alpine">AlpineJS</a>
</div>
</div>
</div>
You can use x-ref on your main image and then $ref in your Alpine data function to set the src property of your main image. You could define your main image something like:
<img x-ref="mainImage" src="URL TO YOUR FIRST IMAGE" />
For each of your thumbnail images, you can do something like:
<img src="URL TO THUMBNAIL" x-on:click="pickPhoto(ARRAY INDEX)">
Your data function can then include something like this:
...
currentPhoto: 0,
photos: [
"URL TO FIRST IMAGE",
...,
"URL TO LAST IMAGE",
],
pickPhoto(index) {
this.currentPhoto = index;
this.$refs.mainImage.src = this.photos[this.currentPhoto];
},
...
I have uploaded a working example here:
https://tailwindcomponents.com/component/tailwind-css-with-alpine-js-photo-gallery
Note that this is deliberately designed to allow you to have different URLs from your thumbnails and main images, so the thumbnails can be intrinsically smaller, and load very quickly. If you are using the same images for both, you can simplify the code significantly. Each of your thumbnails could be done like this:
<img src="URL TO YOUR FIRST IMAGE" x-on:click="$refs.mainImage.src = 'URL TO YOUR FIRST IMAGE'">
With no need for the pickPhoto function or the photos array.
The downside of the simpler approach is that your page will take longer to load because you won't be using smaller images for your thumbnails.
In AlpineJs you could do something like this.
Not tested, just to make you an idea.
myimages()
{
return {
selected: '',
images: [
'images/1.png',
'images/2.png',
'images/3.png',
'images/4.png'
]
}
}
<div x-data="myimages()">
<div>
<img id="main" :src="selected"/>
</div>
<div>
<template x-for="(selimage, index) in images" :key="index">
<img class='small' :src="selimage" #click="selected = selimage"/>
</template>
</div>
</div>
you can for each both of them like this
<div x-data="{image:'0'}">
<div>
#foreach ($image_src as $key => $image)
<a href="">
<img x-show="image==='{{ $key++ }}'"
src="{{$image}}" alt="">
</a>
#endforeach
</div>
<div class=" overflow-x-scroll ">
#foreach ($image_src as $key=> $image)
<a class="mr-1" on- href="">
<img :class="{' border border-way-pink':image==='{{ $key }}'}"
#click.prevent="image='{{ $key++ }}'"
class="w-32 h-24 mr-5" src="{{$image}}" alt="">
</a>
#endforeach
</div>
</div>
I'm using MVC3 with Knockout.js and want to attach some data from the api to my button with data-bind=addContribute in a template. This button should open a pop up box and I need the attached button data on that pop up. How can I do this?
My template:
<div>
<ul data-bind="template: {name: 'membersTemplate', foreach: viewModel.membersList}">
</ul>
</div>
<script id="membersTemplate" type="text/html">
<li>
<div class="fl width165">
<img src=" ${ image } " width="33" height="34" />
<span> ${ memberName } </span>
${ memberType }
</div>
<aside class="fr margint10">
<label> ${ contributions } </label>
<a href="#" class="sprite-add_img" id="openContribute" title="Add Contributes to Goals" data-bind="click: viewModel.addContribute" ></a>
</aside>
</li>
</script>
<script id="membersTemplate" type="text/html">
<li>
<div class="fl width165">
<img data-bind="attr : {src : img}" width="33" height="34" />
<span data-bind="text : memberName"></span>
<span data-bind="text : memberType"></span>
</div>
<aside class="fr margint10">
<label data-bind="text : contributions"></label>
<a href="#" class="sprite-add_img" id="openContribute" title="Add Contributes to Goals" data-bind="click: addContribute" ></a>
</aside>
</li>
</script>
membersList varibale in you code should be next
function SingleMember(img, name, type, contr)
{
var self = this
self.img = ko.observable(img)
self.memberName = ko.observable(name)
self.memberType = ko.observable(type)
self.contributions = ko.observable(contr)
self.addContribute = function() {
//
}
}
window.viewModel = new function()
{
var self = this
self.membersList = ko.observableArray()
self.membersList.push(new SingleMember(/*.... params1*/))
self.membersList.push(new SingleMember(/*.... params2*/))
}
HtML section in _Layout.cshtml
<div id="header">
<div class="logo"><img src="#Url.Content("~/!(IMAGEPATH)!/logo.png")" alt="" /></div>
<div class="fb_like"><img src="#Url.Content("~/!(IMAGEPATH)!/fb_like_btn.png")" alt="" /></div>
<div class="google_plus"><img src="#Url.Content("~/!(IMAGEPATH)!/google_plus.png")" alt="" /></div>
<div class="header_rt">
<ul>
<li>Call us: 1500 258 789</li>
<li>Live chat</li>
<li>My Account</li>
<li>Sign in</li>
</ul>
<div class="search">
<input type="text" value="Type your keyword..." class="srh_txt" />
<input name="Submit" type="submit" value="Submit" class="srh_btn" />
</div>
</div>
</div>
<div id="main">
#RenderBody()
</div>
Html section in Index.cshtml
#{
ViewBag.Title = "Home Page";
}
<div class="clr"></div>
<div id="banner">
<div id="slider"><img src="#Url.Content("~/!(IMAGEPATH)!/banner.jpg")" alt="" /></div>
<div class="banner_rt">
<div class="adv1"><img src="#Url.Content("~/!(IMAGEPATH)!/adv1.jpg")" alt="" /></div>
<div class="adv2"><img src="#Url.Content("~/!(IMAGEPATH)!/adv2.jpg")" alt="" /></div>
</div>
Using bellow code I able to Replace !(IMAGEPATH)! only in _Layout.cshtml
void Application_PostReleaseRequestState(object sender,EventArgs e)
{
if(string.CompareOrdinal(Response.ContentType,"text/html") == 0)
{
Response.Filter = new ResponseFilter(Response.Filter);
}
}
But above described code not affecting child pages like Index.cshtml. Please tell me any event in ASP.NET MVC3 like old protected override void OnPreInit(EventArgs e) of Classic ASP.NET !!!!
I want to know which event effecting all the child pages before rendering in MVC3 ?
Within Base Controller, write the bellow code
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
var response = filterContext.HttpContext.Response;
if (string.CompareOrdinal(response.ContentType, "text/html") == 0)
{
response.Filter = new ResponseFilter(response.Filter);
}
base.OnResultExecuting(filterContext);
}
I have a Razor view that has something like this in:
#foreach (var item in Model.Items)
{
<div class="product">
<a class="hide" href="#">
<img src="#" alt="Hide" />
</a><a href="#">
<img src="#" width ="138" height="140" alt="product name" />
</a>
<h4 class="title">#Html.Raw(#item.Name)</h4>
<span class="price">#item.Price.ToString("C")</span>
</div>
}
This is working well, and outputs the required html
However,
I need to wrap each "row" of with a
<div class="ClearFix"></div> - otherwise the layout gets messy after a few rows.
(In my case, a row is 5 product divs)
Is there any way of doing this?
#foreach (var row in Model.Items.Select((item, index) => new { index, item }))
{
if (row.index % 5 == 0)
{
<div class="ClearFix"></div>
}
<div class="product">
<a class="hide" href="#">
<img src="#" alt="Hide" />
</a>
<a href="#">
<img src="#" width ="138" height="140" alt="product name" />
</a>
<h4 class="title">#Html.Raw(#row.item.Name)</h4>
<span class="price">#row.item.Price.ToString("C")</span>
</div>
}
Shouldn't a simple int i and i % 5 == 0 and i > 5 do the trick?
If you truly need to wrap the contents in the clear fix div ...
#{
var grouping = new List<Item>();
var itemsPerRow = 5;
for (var i = 0; i < Model.Items.Count; i++)
{
var item = Model.Items[i];
grouping.Add(item);
if (i>0 && i%itemsPerRow == itemsPerRow-1)
{
<div class="clear-fix">
#foreach (var thing in grouping)
{
Html.RenderPartial("_ItemPartial", thing);
}
</div>
grouping.Clear();
}
}
}
and then in _ItemPartial.cshtml:
#model Item
<div class="product">
<a class="hide" href="#">
<img src="#" alt="Hide" />
</a><a href="#">
<img src="#" width ="138" height="140" alt="product name" />
</a>
<h4 class="title">#Html.Raw(#Model.Name)</h4>
<span class="price">#Model.Price.ToString("C")</span>
</div>