Im building a MVC4 application to make searches on a wiki document. Everything works great but i have not been able to figure out the best way to make the facets linkable.
i precent the facets on my startpage to make it easier to find keywords you look for:
var products = solr.Query(SolrQuery.All,
new QueryOptions {
Rows = 0,
Facet = new FacetParameters {
Queries = new[] { new SolrFacetFieldQuery("products") }
}
});
foreach(var facet in products.FacetFields["products"]) {
var catagoryFacet = new CategoryFacet(facet.Key, facet.Value);
facetProductList.Add(catagoryFacet);
}
Then i loop through the list in the view like this:
<h2> Products: </h2>
#foreach (var facet in Model)
{
foreach(var item in facet.products) {
<td>#Html.DisplayFor(ModelItem => item.Name), #Html.DisplayFor(ModelItem => item.Count)</td> <br/>
}
But with this approach, when a user clicks the link what happen is that i send the word of facet back to the controller that fire of a search on that keyword since i know it exist.
I know this is kind of a bad way so i am trying to figure out a better way, and since im from sweden the link is broken if i use any of "åäö". It´s possible to handle by javascript but it feels very ugly, so how can i do this in a better way?
I have been looking at the the filter query but how do i make it linkable?
Regards
Jonathan
I solved it by simply put Url.Encode on the Item.Name. Now the search works, as i wanted.
<h2> Products: </h2>
#foreach (var facet in Model)
{
foreach(var item in facet.ProductFacets) {
<td>#Html.DisplayFor(ModelItem => item.Name), #Html.DisplayFor(ModelItem => item.Occurrences)</td> <br/>
}
Related
I have been able to bring back the data from the card table I want based on the following SQL Query in my controller:
SQLstatement = string.Format("select * from cards, cardcollections where isowned = 1 and cards.cardid = cardcollections.cardid and collectionid = {0}", v.CollectionID);
var CardList = db.Cards.SqlQuery(SQLstatement);
return View(CardList.ToPagedList(pageNumber, pageSize));
If I reference just the Cards model it shows the card listing without the extra data I want. I want to be able to display one column from card collections table (NumberOfCopies) in the same view as though it were included in the first table. If I run the query in SQL Server Management Studio, it brings back both tables worth of data by appending the columns of cardcollections to the cards table.
I made a view but cannot get it to pass correctly. I get this error:
The model item passed into the dictionary is of type 'PagedList.PagedList`1[MTG.Models.Card]', but this dictionary requires a model item of type 'PagedList.IPagedList`1[MTG.Models.ViewCardCollectionView]'.
I understand that I am not passing the ViewCardCollectionView because of the way I have the CardList variable set. I don't know how to do the query I want while using the correct ViewModel.
#model IPagedList<MTG.Models.ViewCardCollectionView>
#foreach (var card in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { id=card.Cards.CardID }) |
#Html.ActionLink("Details", "Details", new { id=card.Cards.CardID }) |
#Html.ActionLink("Delete", "Delete", new { id=card.Cards.CardID }) |
#Html.DisplayFor(modelItem => card.CardCollections.NumberofCopies)
</td>
<td>
<b>#Html.DisplayFor(modelItem => card.Cards.Title)</b><br />
#Html.DisplayFor(modelItem => card.Cards.MainType.Title) - #Html.DisplayFor(modelItem => card.Cards.SubType.Title) #Html.DisplayFor(modelItem => card.Cards.AdditionalType)<br />
AND SO ON...
My ViewModel is:
public class ViewCardCollectionView
{
public Card Cards { get; set; }
public CardCollection CardCollections { get; set; }
I have tried many variations on querying in the controller and trying to bring the viewmodel back in the return View() but to no avail. Any advice would be greatly appreciated. :)
Honestly, the easiest way to handle this would be to familiarize yourself with the Entity Framework and start using that. You're not only writing a lot of excess code you don't have to, but you're opening up your application to SQL Injection attacks by manually building SQL statements based on user input (I'm not sure where v.CollectionID comes from but I would assume somewhere in the app there's a security hole even if it's not right there).
I was able to get this to work by changing the controller to the following:
var viewModel = from c in db.Cards
join j in db.CardCollections on c.CardID equals j.CardID
where (j.IsOwned == true) && (j.CollectionID == v.CollectionID)
select new ViewCardCollectionView { Cards = c, CardCollections = j };
return View(viewModel);
I need to have multiple radio button groups in my form like this:
I know it's simply done by specifying the same "name" html attribute for each group.
HOWEVER
MVC doesn't let you specify your own name attribute when using html helper like this:
#Html.RadioButtonFor(i => item.id, item.SelectedID, new { Name = item.OptServiceCatId })
Because it looks at each tag's "name" attribute (not "id") to map/bind the form to the model which the controller receives, etc.
Some said that specifying each with the same "GroupName" attribute will solve the problem, but it didn't work either.
So, is there any way which works ?
EDIT:
Here's my view (simplified):
#model Service_Provider.ViewModels.SelectOptServicesForSubServiceViewModel
#foreach (var cat in Model.OptServices)
{
//A piece of code & html here
#foreach (var item in cat.OptItems.Where(i => i.MultiSelect == false))
{
#Html.RadioButtonFor(i => item.id, item.SelectedID, new { GroupName = item.OptServiceCatId })
<br />
}
}
NOTE:
My model is a List<OptServices>:
public List<OptServices> Cats {get; set;}
And OptServices has a List of OptItems inside:
public class OptServices
{
//a few things
public List<OptItems> Items {get; set;}
}
all you need is to tie the group to a different item in your model
#Html.RadioButtonFor(x => x.Field1, "Milk")
#Html.RadioButtonFor(x => x.Field1, "Butter")
#Html.RadioButtonFor(x => x.Field2, "Water")
#Html.RadioButtonFor(x => x.Field2, "Beer")
Ok here's how I fixed this
My model is a list of categories. Each category contains a list of its subcategories.
with this in mind, every time in the foreach loop, each RadioButton will have its category's ID (which is unique) as its name attribue.
And I also used Html.RadioButton instead of Html.RadioButtonFor.
Here's the final 'working' pseudo-code:
#foreach (var cat in Model.Categories)
{
//A piece of code & html here
#foreach (var item in cat.SubCategories)
{
#Html.RadioButton(item.CategoryID.ToString(), item.ID)
}
}
The result is:
<input name="127" type="radio" value="110">
Please note that I HAVE NOT put all these radio button groups inside a form. And I don't know if this solution will still work properly in a form.
Thanks to all of the people who helped me solve this ;)
I fixed a similar issue building a RadioButtonFor with pairs of text/value from a SelectList. I used a ViewBag to send the SelectList to the View, but you can use data from model too. My web application is a Blog and I have to build a RadioButton with some types of articles when he is writing a new post.
The code below was simplyfied.
List<SelectListItem> items = new List<SelectListItem>();
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("Texto", "1");
dictionary.Add("Foto", "2");
dictionary.Add("Vídeo", "3");
foreach (KeyValuePair<string, string> pair in objBLL.GetTiposPost())
{
items.Add(new SelectListItem() { Text = pair.Key, Value = pair.Value, Selected = false });
}
ViewBag.TiposPost = new SelectList(items, "Value", "Text");
In the View, I used a foreach to build a radiobutton.
<div class="form-group">
<div class="col-sm-10">
#foreach (var item in (SelectList)ViewBag.TiposPost)
{
#Html.RadioButtonFor(model => model.IDTipoPost, item.Value, false)
<label class="control-label">#item.Text</label>
}
</div>
</div>
Notice that I used RadioButtonFor in order to catch the option value selected by user, in the Controler, after submit the form. I also had to put the item.Text outside the RadioButtonFor in order to show the text options.
Hope it's useful!
I was able to use the name attribute that you described in your example for the loop I am working on and it worked, perhaps because I created unique ids? I'm still considering whether I should switch to an editor template instead as mentioned in the links in another answer.
#Html.RadioButtonFor(modelItem => item.Answers.AnswerYesNo, "true", new {Name = item.Description.QuestionId, id = string.Format("CBY{0}", item.Description.QuestionId), onclick = "setDescriptionVisibility(this)" }) Yes
#Html.RadioButtonFor(modelItem => item.Answers.AnswerYesNo, "false", new { Name = item.Description.QuestionId, id = string.Format("CBN{0}", item.Description.QuestionId), onclick = "setDescriptionVisibility(this)" } ) No
You can use Dictonary to map
Assume Milk,Butter,Chesse are group A (ListA)
Water,Beer,Wine are group B
Dictonary<string,List<string>>) dataMap;
dataMap.add("A",ListA);
dataMap.add("B",ListB);
At View , you can foreach Keys in dataMap and process your action
On this page, a user fills out a web form, and it gets added to the list when created.
I want to filter the list so a logged in user will only see forms they made themselves.
I have some Razor code that runs a foreach loop through all available items, and I have Javascript that rips the currently logged in user's info.
is it possible to assign this data to a var in the razor code?
ex.
#{var user = getUser(); //want something like this }
#foreach (var item in Model) {
//add check if item.name == user.name here
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
etc etc
<script>
function getUser() {$.getJSON('GetLoggedUserInfo', function(data) {
return data;
});
</script>
I do not think it is a good idea to have this logic in a view. View should be as 'dumb' as possible.
You could make item filtering at data storage level or at least in controller:
return View(items.Where(x => x.name == user.name))
There is an easier way. You can get current user properties using:
HttpContext.Current.User
I'm trying to do the same as this ASP.NET MVC Using two inputs with Html.BeginForm question describes but with enough difference that I don't really know hwo to apply it on my project:
I have a view that has 3 dropdownlists(profilelist, connected salarylist & not connected salarylist)
Looks like this:
<div class="row bgwhite">
#using (Html.BeginForm("GetConnectedSalaries", "KumaAdmin", FormMethod.Get, new { Id = "ProfileListForm" }))
{
<div class="four columns list list1">
#Html.DropDownList("Profiles", (SelectList) ViewBag.Profiles, "--Välj profilgrupp--",
new
{
//onchange = "$('#ProfileListForm')[0].submit();"
// Submits everytime a new element in the list is chosen
onchange = "document.getElementById('ProfileListForm').submit();"
})
</div>
}
#using (Html.BeginForm("Index", "KumaAdmin", FormMethod.Get, new { Id = "SalaryListForm" }))
{
<div class="four columns list list2" style="margin-top:-19px;">
#Html.DropDownList("Salaries", (SelectList) ViewBag.Salaries, "--Kopplade LöneGrupper--")
</div>
}
#using (Html.BeginForm("GetNOTConnectedSalaries", "KumaAdmin", FormMethod.Get, new { Id = "NotConSalaryListForm" }))
{
<div class="four columns list list2" style="margin-top:-19px;">
#Html.DropDownList("Salaries", (SelectList)ViewBag.NotConSalaries, "--Ej Kopplade LöneGrupper--")
<input style="float: left;" type="submit" value="Knyt" />
</div>
}
</div>
as you can see above when i change an element i the profile list i have script code that submits the form and calls the following actionresult that populates my "connected salarylist".
[HttpGet]
public ActionResult GetConnectedSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetConnectedSalaries(Profiles);
ViewBag.Salaries = new SelectList(Model.SalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
What I wan't to do:
When I chose a element in the profilelist i would like to call 2 actionresults, the one that i have shown above AND a second one that will populare my third list that will contain "not connected salaries".
Second Actionresult:
public ActionResult GetNOTConnectedSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetNOTConnectedSalaries(Profiles);
ViewBag.NotConSalaries = new SelectList(Model.NotConSalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
I don't want to do this with AJAX/JSON, strictly MVC.
I read the question that i linked above but did not know how to apply it to my project or if it is even possible to do the same.
If more info is needed ask and i will do my best to provide it.
Thank you!
I was so sure that the best way to do this was to have two actionresults that i was totaly blinded to the soloution that i could call both my db methods from the same actionresult and populate both of the lists.
Simple soloution:
[HttpGet]
public ActionResult GetSalaries(int Profiles = -1)
{
Model.SalaryGroups = AdminManager.GetConnectedSalaries(Profiles);
ViewBag.Salaries = new SelectList(Model.SalaryGroups, "Id", "SalaryName", "Description");
Model.NotConSalaryGroups = AdminManager.GetNOTConnectedSalaries(Profiles);
ViewBag.NotConSalaries = new SelectList(Model.NotConSalaryGroups, "Id", "SalaryName", "Description");
return (Index());
}
Sorry if I wasted your time:( but hopefully this will help others that attempt the same.
However if there is a way to do this in two actionresults then I will leave the question as open, would be interesting to see how it is done.
I get this strange "error". When i run my app (edit action i.e update) i get duplicate values stored in my dB. If i use the debugger, step by step, its working (no duplicates)...
It's a Many-to-Many Relationship so don't bother the Courses NULL value in the images, just trying to figure things out...
All Help is appreciated!
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
var course = db.Courses
.Where(c => c.Id == model.CourseId)
.Single();
if (ModelState.IsValid)
{
course.Name = model.CourseName;
course.Description = model.CourseDescription;
course.Students = model.Students;
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
I get my viewModel back. All good.
My Old values from dB. I want to update this data. So everything is still good...
My old values are updated to my new Values. Great!
Ok everything works great IF I step with debugger like this. But if i run the app i will get duplicates.... Anyone?
New content:
My Edit-view
#model ValueInjecter.Web.Models.CourseStudentViewModel
#{
ViewBag.Title = "Edit"; }
Edit Course
#using (Html.BeginForm()) {
#Html.HiddenFor(c => Model.CourseId)
#Html.LabelFor(c => Model.CourseName)
#Html.EditorFor(c => Model.CourseName)
#Html.LabelFor(c => Model.CourseDescription)
#Html.EditorFor(c => Model.CourseDescription)
</div>
<hr />
<h2>Students</h2>
<div class="editor-field">
#for (int i = 0; i < Model.Students.Count(); i++)
{
<div style="border: dotted 1px; padding: 5px; margin: 10px;">
#Html.HiddenFor(s => s.Students[i].Id)
#Html.LabelFor(s => s.Students[i].Name[i + 1])
#Html.EditorFor(s => s.Students[i].Name)
</div>
}
</div>
<p>
Number of Students:
<b>#Html.DisplayFor(s => Model.StudentCount)</b>
</p>
<hr />
<p>
<input type="submit" value="Save" />
</p> }
It probably works in the debugger because by inspecting course.Students collection in a property watch window you trigger actually a second database query (after the query that loads the course) due to lazy loading of the Students collection. (Your Course.Students collection is most likely declared as virtual.) If you run without debugger no lazy loading occurs and course.Students stays empty.
You can force that the course.Students collection is always loaded by using eager loading instead of lazy loading (which also saves the second database roundtrip):
var course = db.Courses
.Include(c => c.Students)
.Where(c => c.Id == model.CourseId)
.Single();
Honestly I have no clue why your code works correctly with the loaded collection (in the debugger) and why it works at all. Assigning a complete detached collection like this: course.Students = model.Students, and then just setting the state of the parent to Modified is normally not enough to update a child collection.
But I see "ValueInjecter" in your screenshots. Maybe there is some automatic mapping magic happening that does (accidentally?) the right thing to get a working update.
Ok I finally figured out the solution of my problem. Of course much easier than first thought.
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
if (ModelState.IsValid)
{
var course = db.Courses.Find(model.CourseId);
course.Name = model.CourseName;
course.Description = model.CourseDescription;
if(model.Students != null)
{
foreach (var item in model.Students)
{
db.Entry(item).State = System.Data.EntityState.Modified;
}
}
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
Still using the view ive pasted above.