Umbraco GetCropUrl - umbraco

I'm trying to set the selected crom for my image, But I'm stuck and cant figure it out what I'm doing wrong.
ImageWithTextHover.cs
public class ImageWithTextHover
{
public string Text { get; private set; }
public Link Url { get; private set; }
public MediaItem Image { get; private set; }
public string Crop { get; private set; }
public ImageWithTextHover(IPublishedContent content)
{
Text = content.GetPropertyValue<string>("text");
Url = content.GetPropertyValue<MultiUrls>("link").FirstOrDefault();
Crop = content.GetPropertyValue<string>("imageCrop");
Image = content.GetMediaItem("image", Crop);
}
}
cshtml
#using Umbraco.Site.Extensions.Models.DocumentTypes.Grid
#inherits UmbracoTemplatePage
#{
Layout = null;
ImageWithTextHover imagehover = new ImageWithTextHover(Model.Content);
}
<div class="imageWithTextHover">
<div class="row">
<div class="col-sm-12" style="padding: 0;">
<div class="image">
<img src="#imagehover.Image.Url" />
<div class="text">
#Html.Raw(imagehover.Text)
</div>
</div>
<img src="#Url.GetCropUrl(Model.Content, imagehover.Image.Url, imagehover.Crop)" />
</div>
</div>
</div>
#imagehover.Crop is equal to
1:1 - Square

I'm not sure why you're making this so hard on yourself. The easiest way to get a crop is to delete the cs part, use Razor and do this in your cshtml:
If you have set an Image Cropper with specific crops:
<img src="#Url.GetCropUrl(Model.Content, "yourCropperAlias", "yourCropAlias")" />
If you just want a standard crop without the Image Cropper:
#if (Model.Content.HasValue("image"))
{
<img src="#Url.GetCropUrl(Model.Content, propertyAlias: "yourCropperAlias", height: 300, width: 400)" />
}
There's a guide here about crops, maybe it will help. Of course, that's assuming you're using Umbraco 7 and above, because if you're using for example Umbraco 6, well crops are a whole different story.

Related

Asp.net core MVC fetch image from DB based on the Category

I am sorry to bother with simple matters but i really cannot find a way out of this problem.
I am building a Gallery, which container different fields, one of those is Category.
Category Class is a public Enum, and i would like to retrieve all the images in the Database and display them in View based on my Category selection.
Here you can find the code that i wrote so far.
View:
<form method="get" asp-controller="Gallery" asp-action="index">
<div style="height:60px;" class="container">
<div class="row">
<div class="col-md-5">
<div class="row" style="padding-top:10px;">
<div class="col-md-5">
#Html.Editor("Name", new { htmlAttributes = new { #class = "form-control", placeholder = "Name..." } })
</div>
</div>
</div>
<div class="col-md-5">
<select class="custom-select form-control mr-sm-2" asp-items="Html.GetEnumSelectList<Category>()"></select>
</div>
<div class="col-md-1">
<div class="row" style="padding-top:10px; padding-right:20px;">
<button type="submit" name="submit" class="btn btn-success form-control" value="submit">
<i class="fas fa-search fa-1x"></i>
</button>
</div>
</div>
</div>
</div>
</form>
Controller:
public IActionResult Index(string Name, Category category)
{
var model = _galleryRepository.GetAllImages();
StringBuilder param = new StringBuilder();
param.Append("&Name=");
if (Name != null)
{
param.Append(Name);
}
if(Name != null)
{
model = _galleryRepository.SearchName(Name);
}
if(category != Category.All)
{
model = _galleryRepository.SearchCategory(category);
}
return View(model);
}
Model Category:
public enum Category
{
All,
Photography,
Portrait,
Nature
}
Model Gallery:
public class Gallery
{
public int Id { get; set; }
public int Like { get; set; }
public string Comment { get; set; }
[Required]
[MaxLength(40, ErrorMessage ="Name cannot exceed 40 characters")]
public string Name { get; set; }
[Required]
[MaxLength(100, ErrorMessage = "Description cannot exceed 100 characters")]
public string Description { get; set; }
[Required]
public Category Category { get; set; }
public string PhotoPath { get; set; }
}
I did Managed to create a search form based on the Name of the image and it works just fine. But when it come to retrieve the images based on the Category Selection, it does not work.
i used a breakpoint on the Controller on the If statment related to category, and i realized that the condition fires but the model inside no.
So i am asking to the expert for an explanation about how to fix it as it the first time that i work with Enum and retrieving datas based on Enum classes.
Thank you so much for your help and i hope i made clear my problem.
Change your view like below,then you could pass the selected item to category:
#model Gallery
<form method="get" asp-controller="Gallery" asp-action="index">
//...
<div class="col-md-5">
<select asp-for="Category" class="custom-select form-control mr-sm-2" asp-items="Html.GetEnumSelectList<Category>()"></select>
</div>
//...
</form>
The default model binder won't work with Enum types. Either you need to change the parameter to of type string and convert it to it's equivalent enum type before performing the comparisions OR provide your own implementation of model binder and override the default one. If I were you, I will go with the simplest solution like below,
public IActionResult Index(string Name, string selectedCategory)
{
var category = Enum.Parse(typeof(Category),selectedCategory,true);
var model = _galleryRepository.GetAllImages();
StringBuilder param = new StringBuilder();
param.Append("&Name=");
if (Name != null)
{
param.Append(Name);
}
if(Name != null)
{
model = _galleryRepository.SearchName(Name);
}
if(category != Category.All)
{
model = _galleryRepository.SearchCategory(category);
}
return View(model);
}

Comments with replies won't show properly (ASP.NET MVC)

(Reposted question, since the other one was put on hold and then edited but not reopened)
I have a problem with showing comment replies in my comment section on my website. I have made it so there is a Original Comment and that comment can have subcomment (replies) and the way I have set up my code it does work, but if there are 2 original comments and 1 reply on in one section, then it shows the reply og both of them, even though I've coded it to only show on a specific original comment.
Comment model:
namespace ComicbookWebpage.Models
{
public class ComicComment
{
public int Id { get; set; }
public string Comment { get; set; }
public DateTime Posted { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public int ComicId { get; set; }
public Comic Comic { get; set; }
public List<SubComicComment> SubComicComments { get; set; }
}
}
SubComment model (reply):
namespace ComicbookWebpage.Models
{
public class SubComicComment
{
public int Id { get; set; }
public string CommentText { get; set; }
public DateTime Posted { get; set; }
public SubComicComment() {
Posted = DateTime.Now;
}
public string UserId { get; set; }
public ApplicationUser User { get; set; }
public int ComicId { get; set; }
public Comic Comic { get; set; }
public int OriginalCommentId { get; set; }
public ComicComment ComicComment { get; set; }
}
}
Here's my viewmodel I use for all my data (vm):
namespace ComicbookWebpage.Models.ViewModels
{
public class ComicVM
{
public Comic Comic { get; set; }
public Series Series { get; set; }
public List<ComicComment> ComicComments { get; set; }
public List<SubComicComment> SubComicComments { get; set; }
}
}
So as you can see there is an "OriginalCommentId" in my subcomments table, so that I can tell my subcomments what original comment they belong to, so they're only shown under that specific comment. But the problem is like I said above that it shows my subcomment under 2 different original comments on the same page, if the page has 2 original comments, here's an image:
(Image) Comments in view (Browser SS)
On the right side of every comment, you can see an ID, it's the ID that the comment has and you can clearly see that the ID 9 has a subcomment with ID 2, which is totally wrong according to my coding. Because I'm telling my list to render the data where the original comment id is the same as subcomment's OriginalCommentId, so they should both have ID 9, but the subcomment has ID 2 for some reason...
Here's the controller code (Look at vm.SubComicComments):
public ActionResult Comic(int id)
{
ComicVM vm = new ComicVM();
vm.Comic = db.Comics.Include(m => m.Series).Where(m => m.Id == id).FirstOrDefault();
vm.Series = db.Series.FirstOrDefault();
vm.ComicComments = db.ComicComments.Where(m => m.Comic.Id == id).ToList();
vm.SubComicComments = db.SubComicComments.Where(m => m.ComicId == id && m.ComicComment.Id == m.OriginalCommentId).ToList();
db.Users.ToList();
return View(vm);
}
And here's the view code:
#using Microsoft.AspNet.Identity
#using System.Data.Entity;
#model ComicbookWebpage.Models.ViewModels.ComicVM
#{
ViewBag.Title = #Model.Comic.Title;
}
<a class="btn btn-default" href="/Series/Details/#Model.Comic.SeriesId"><i class="glyphicon glyphicon-menu-left"></i> Back</a>
<hr />
<h5><b>Title:</b> #Model.Comic.Title</h5>
<h5><b>Series:</b> #Model.Comic.Series.Title</h5>
<h5><b>Pages:</b> #Model.Comic.PageAmount</h5>
<hr />
<h4><i class="glyphicon glyphicon-comment"></i> Leave a comment:</h4>
<br />
#if (User.Identity.IsAuthenticated)
{
<div class="col-sm-1">
<div class="thumbnail">
<img class="img-responsive user-photo" src="https://ssl.gstatic.com/accounts/ui/avatar_2x.png">
</div><!-- /thumbnail -->
</div><!-- /col-sm-1 -->
<div class="col-sm-5">
<form action="/Series/Comic/#Model.Comic.Id" method="post">
<input type="hidden" name="Posted" value="#DateTime.Now" />
<input type="hidden" name="UserId" value="#User.Identity.GetUserId()" required />
<input type="hidden" name="ComicId" value="#Model.Comic.Id" />
<textarea class="form-control form-text" type="text" name="Comment" placeholder="Type your comment..." required></textarea>
<br />
<button type="submit" class="btn bg-dark">Send</button>
</form>
</div><!-- /col-sm-5 -->
}
else
{
<h5>You have to be logged in to post a comment.</h5>
<p>Click here to login</p>
}
<div class="row">
<div class="col-md-12">
#if (Model.ComicComments.Count > 0)
{
<h4>(#Model.ComicComments.Count) Comments:</h4>
}
else
{
<h4>0 Comments:</h4>
<p>There are currently no comments posted on this comic book.</p>
}
</div>
</div>
#foreach (var Comment in Model.ComicComments.Where(m => m.ComicId == m.Comic.Id))
{
<div class="comments-container">
<ul id="comments-list" class="comments-list">
<li>
<div class="comment-main-level">
<!-- Avatar -->
<div class="comment-avatar"><img src="https://i9.photobucket.com/albums/a88/creaticode/avatar_1_zps8e1c80cd.jpg" alt=""></div>
<!-- Contenedor del Comentario -->
<div class="comment-box">
<div class="comment-head">
<h6 class="comment-name by-author">#Comment.User.UserName</h6>
<span>posted on #Comment.Posted.ToShortDateString()</span><i>ID: #Comment.Id</i>
</div>
<div class="comment-content">
#Comment.Comment
</div>
</div>
</div>
<!-- Respuestas de los comentarios -->
<ul class="comments-list reply-list">
#if (Model.SubComicComments.Count > 0)
{
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == m.ComicComment.Id))
{
<li>
<!-- Avatar -->
<div class="comment-avatar"><img src="https://i9.photobucket.com/albums/a88/creaticode/avatar_2_zps7de12f8b.jpg" alt=""></div>
<!-- Contenedor del Comentario -->
<div class="comment-box">
<div class="comment-head">
<h6 class="comment-name">#SubComment.User.UserName</h6>
<span>posted on #SubComment.Posted.ToShortDateString()</span><i>ID: #SubComment.OriginalCommentId</i>
</div>
<div class="comment-content">
#SubComment.CommentText
</div>
</div>
</li>
}
}
</ul>
</li>
</ul>
</div>
}
If you guys can figure out what the heck is wrong here, I would appreciate it. To me the code is pretty logical and should work, but it doesn't, and I've tried so many things but no luck.
Thank you in advance.
For your SubComments foreach statement:
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == m.ComicComment.Id))
Should be:
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == Comment.Id))
No? You want to check SubComment.OriginalCommentId against the id in the Comment variable declared in your enclosing Comments iteration.
As an aside, in your first foreach statement, I don't think the where clause is doing anything:
#foreach (var Comment in Model.ComicComments.Where(m => m.ComicId == m.Comic.Id))
ComicID == Comid.Id should always be true as long as your includes have loaded...

How manage a View (Validation and Binding etc) for Different models in a view in MVC

Consider a user can create a Sale advertising (Post model). but every advertising have different properties depend on its Group. Properties are not certain and can be added by admin with different constraints(Required. MinLength etc.)
I define a class like this:
public class Property
{
public int Id { get; set; }
public int Priority { get; set; }
[Required()]
public InputType Type { get; set; }
[Required()]
[MaxLength(150)]
public string Title { get; set; }
[Index(IsUnique=true)]
[Required()]
[MaxLength(100)]
public string Values { get; set; }
[MaxLength(100)]
public string Description { get; set; }
public ICollection<GroupProperty> GroupProperties { get; set; }
public ICollection<PostProperty> PostProperties { get; set; }
}
For example admin can add a model's car property to cars group. after that users must fill a model car field for advertisings in car group.
Create view for advertising is like this:
#model IEnumerable<Property>
<section>
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<h1>New Advertising</h1>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
foreach (var item in Model)
{
#Html.EditorFor(m => item)
}
<button type="submit">hvah</button>
}
</div>
<div class="col-md-6">
</div>
</div>
</div>
</section>
Ah everything goes harder! I have a Editor template for Property class like this:
#model Property
#helper Helper(Property model)
{
switch (model.Type)
{
case WebSite.Models.DomainModels.InputType.NonNegative:
{
<div class="form-group">
<label for="#(model.Name)">#(model.Title)</label>
<span class="field-validation-valid text-danger" data-valmsg-for="#(model.Name)" data-valmsg-replace="true"></span>
<input class="form-control text-box single-line valid" data-val="true"
name="#(model.Name)" type="number" value="0"/>
</div>
return;
}
case WebSite.Models.DomainModels.InputType.RequiredShortString:
{
<div class="form-group">
<label for="#(model.Name)">#(model.Title)</label>
<span class="field-validation-valid text-danger" data-valmsg-for="#(model.Name)" data-valmsg-replace="true"></span>
<input class="form-control text-box single-line" data-val="true"
id="#(model.Name)" name="#(model.Name)" type="text" value="BB"/>
</div>
return;
}
}
}
#Helper(Model)
After all i have Client validation for properties. with hard code i can validate them in server side too. but new problem is Binding! if server side validation goes wrong i need to pass a model to view again. so i am think im doing this with a wrong way. can some one help me? maybe about how solve my problem or a better way to implement this? a simple way to use MVC validation On a complex model like this?
I think you want to create a class and validate ModelState. you can do it like-
Example:
You can pass your model state around like this:
public class MyClass{
public static void errorMessage(ModelStateDictionary ModelState) {
if (something) ModelState.AddModelError("", "Error Message");
}
}
Use in controller:
MyClass.errorMessage(ModelState);
If you need more information about modaestate validation outside then you can fiend more help from this link.

Repeating Partial View in ASP.net MVC 4

Guys I am trying to generate notices on my test web application for learning MVC. This has functionality same as facebook's newsfeed. I have created a model of notice, a partial view of notice and executing a stored procedure in controller to retrieve the values from database (SQL server 2012).
Now what I want to do is, upon loading the page, it should display 3 notices (partial view repeated 3 times with different values each time) and then on scroll event it should load 5 more notices..
This is my model :
public class Notice
{
public string Subject { get; set; }
public DateTime Date { get; set; }
public string Department { get; set; }
public string Body { get; set; }
public string NoticeImage { get; set; }
public string Icon { get; set; }
}
This is my partial view :
<article class="feed payroll new" data-slide="items1">
<div class="sideicon"><img src="#Model.notice.Icon" alt="payroll" width="52" height="52"></div>
<section>
<header>
<h3> #Model.notice.Subject</h3>
<p><span> #Model.notice.Department</span> | #Model.notice.Date </p>
</header>
<article>
#Model.notice.Body
<br />
<img src="#Model.notice.NoticeImage" width="100" height="100"/>
</article>
</section>
</article>
This is my controller :
Query = "uSP_GetNotices";
cmd = new SqlCommand(Query, Connection);
cmd.CommandType = CommandType.StoredProcedure;
DataTable dtNotice = new DataTable();
Connection.Open();
dtNotice.Load(cmd.ExecuteReader());
Connection.Close();
Notice objNotice = new Notice();
objNotice.Subject = dtNotice.Rows[0]["Subject"].ToString();
objNotice.Date = Convert.ToDateTime(dtNotice.Rows[0]["IssueDate"]);
objNotice.Department = dtNotice.Rows[0]["Department"].ToString();
objNotice.Body = dtNotice.Rows[0]["Body"].ToString();
objNotice.NoticeImage = dtNotice.Rows[0]["NoticeImage"].ToString();
objNotice.Icon = dtNotice.Rows[0]["Icon"].ToString();
//returning Main view....
Now how do I go about getting that functionality ? how do I repeating partial view multiple times with different values each time ?
In the above code, I am only entering row 0 of datatable to model...I want to do this dynamically i.e. change rows per partial view. I would really appreciate some help.
EDIT :
NoticeUserWrapper
public class NoticeUserWrapper
{
public User user;
public List<Notice> noticeList;
public NoticeCount noticeC;
public NoticeUserWrapper()
{
user = new User();
noticeList = new List<Notice>();
noticeC = new NoticeCount();
}
}
Pass the List to main view and then in loop call Html.RenderPartial like this:
#model List<NameSpace.Models.Notice>
#forach(var item in Model)
{
Html.RenderPartial("YourPartialView", item)
}
Partial View:
#model NameSpace.Models.Notice
<article class="feed payroll new" data-slide="items1">
<div class="sideicon"><img src="#Model.notice.Icon" alt="payroll" width="52" height="52"></div>
<section>
<header>
<h3> #Model.notice.Subject</h3>
<p><span> #Model.notice.Department</span> | #Model.notice.Date </p>
</header>
<article>
#Model.notice.Body
<br />
<img src="#Model.notice.NoticeImage" width="100" height="100"/>
</article>
</section>
</article>
UPDATED:
You need to use jquery and ajax to achieve this, i implemented this in my one project and made a tutorial you can see here:
http://developmentpassion.blogspot.com/2013/12/infinite-scroll-paging-in-aspnet-mvc-4.html
You can do using ajax:
//you method on the controller
public ActionResult GetNotice(Param param)
{
//retrive notice
IList<Notice> viewModels = GetNotices();
return PartialView("_NoticePartial",viewModels)
}
JavaScript:
$(document).ready(function()
{
//ID of your div
$("#mynotices").scroll(function() {
var param = "your param";
$.post("/Notice/GetNotice",{param: param}, function(data) {
$("mynotices").append(data);//append all notice retrieved from your controller
});
});
});
the partial view
#model IList<Notice>
#foreach(item in Model)
{
<article class="feed payroll new" data-slide="items1">
<div class="sideicon"><img src="#Model.notice.Icon" alt="payroll" width="52" height="52"></div>
<section>
<header>
<h3> #item.notice.Subject</h3>
<p><span> #item.notice.Department</span> | #item.notice.Date </p>
</header>
<article>
#item.notice.Body
<br />
<img src="#item.notice.NoticeImage" width="100" height="100"/>
</article>
</section>
</article>
}
Index page:
<div id="mynotices">
//your notice
</div>

how to bind more than one model with single view?

Guys I have tried to use more than one Models with single view.
but I could not found the solution how to implement it.
I want to use One View data in Single past and the other in another part..
I have used the following code..
this is one view
#Html.Partial("Sidebar")
this is another view
<!-- start content -->
<div id="content">
<div class="post">
<h1 class="title">
Add New Post
</h1>
<p></p>
<div class="entry">
#using (Html.BeginForm())
{
<div>
<div style="display:inline;">
<div style="display: inline; float: left;">
#Html.Label("lblcategory", "Category", new { style = "Width:100px; float: left;" })
<div style="width: 150px; height: 60px; overflow-y: scroll; display: inline; float: left;">
#for (int i = 0; i < (int)TempData["Rows"]; i++)
{
for (int j = 0; j < (int)TempData["Cols"]; j++)
{
<input id="Checkbox + #i" name = "Category" type="checkbox" style="width:50px;" value="#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]"/>
#TempData["[" + i.ToString() + "][" + j.ToString() + "]"]
}
}
#*#Html.LabelFor(model => model.CategoryName)*#
</div>
<div style="float:right;">
<label id="lblcategoryrequired" style="color:Red">#Html.ValidationMessageFor(model => model.CategoryName)</label>
</div>
</div>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblsubjet", "Subject", new { style = "Width:100px; float: left;" })
#*#Html.TextBox("txtsubject", "", new { style = "Width:700px;" })*#
#Html.TextBoxFor(model => model.PostSubject, new { style = "Width:400px; maxlength=400;" })
<label id="lblsubjectrequired" style="color:Red">#Html.ValidationMessageFor(model => model.PostSubject)</label>
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblcontent", "Content", new { style = "Width:100px; float: left; Vertical-align:top;" })
#*#Html.TextArea("txtcontent","", new { style = "Width:700px; height:200px; maxlength=700;" })*#
#Html.TextAreaFor(model => model.PostContent, new { style = "Width:400px; height:200px; maxlength=400;" })
</p>
</div>
<div>
<p style="display: inline; float: left;">
#Html.Label("lblblank", "a", new { style = "Width:100px; float: left; Color:#372412" })
<input type="submit" value="Add" id="btnadd" style="width: 100px;" class="button" />
&nbsp&nbsp&nbsp&nbsp
<a id="Cancel" href="~/Home/Home"> <input type="button" value="Cancel" id="btncancel" class="button" style="width: 100px;" /></a>
</p>
</div>
</div>
#Html.ValidationSummary(true)
}
</div>
</div>
</div>
</div>
I don't understand your question 100%. But if I were to understand it then I don't think it will work the way that you need it to work (I might be mistaken). I would suggest that you move away from your partial view and just pass in one view model that you can use to populate both sections. View models are there to represent your data on a view.
I'm going to give you a basic sample that you can modify and use in your scenario. Lets say we have a customer and this customer can have 1 or many addresses. So a basic representation of these 2 models could look like this:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Address> Addresses { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
}
And now on your details view you want to display the customer's details and the addresses of this customer. So we have 2 models (customer and address) that you are displaying on 1 view.
public ActionResult Details(int id)
{
Customer customer = customerRepository.GetById(id);
if (customer != null)
{
customer.Addresses = addressRepository.GetAddressesForCustomer(customer.Id);
}
// The above 2 steps can be done in 1 repository call
// Now populate your view model with the above details
// This can also be 1 or 2 lines when you use something like Auto Mapper
CustomerDetailsViewModel viewModel = new CustomerDetailsViewModel
{
viewModel.CustomerId = customer.Id,
viewModel.CustomerFirstName = customer.FirstName,
viewModel.CustomerLastName = customer.LastName,
viewModel.CustomerAddresses = customer.Addresses
};
return View(viewModel);
}
Your view model:
public class CustomerDetailsViewModel
{
public int CustomerId { get; set; }
public string CustomerFirstName { get; set; }
public string CustomerLastName { get; set; }
public IEnumerable<Address> CustomerAddresses { get; set; }
}
So now you have 1 view model populated from 2 different models. Now all that you have to do on your view is to use this view model to display data:
#model YourProject.ViewModels.Customers.CustomerDetailsViewModel
#Model.CustomerId<br />
#Model.CustomerFirstName<br />
#Model.CustomerLastName<br /><br />
#foreach (var address in #Model.CustomerAddresses)
{
<div>
#address.Id<br />
#address.AddressLine1<br />
#address.AddressLine2<br />
#address.AddressLine3<br />
</div>
}
I hope this helps.
You should use a view model that represents the data required to render your view. You could either expose the models directly on the view model (violating LoD), or delegate the calls to the view model to the underlying models (violating the DRY principle).

Resources