How to group project results by Taxonomy Terms - orchardcms

I have a ContentType Animal which has a Taxonomy field species.
look at this posthttp://orchardpros.net/tickets/10636 and (http://www.ideliverable.com/blog/ways-to-render-lists-of-things) for a good explanation.
I runed the code,but It have 2 erro.
1.var speciesField = item.Animal.Species;----gave erro: CS1061 ,"Orchard.ContentManagement.ContentItem' does not contain a definition Animal".
2.var items = speciesDictionary[speciesTerm];----gave erro:CS0136 " A local or parameter named 'items' cannot be declared in this scope because that name is used in an enclosing local.
please help!
#using Orchard.ContentManagement
#using Orchard.Taxonomies.Models
#{
var items = ((IEnumerable<ContentItem>)Model.ContentItems);
var speciesDictionary = new Dictionary<TermPart, IList<ContentItem>>();
// Collect categories and their items.
foreach (var item in items) {
var speciesField = item.Animal.Species; // Assumes that the species field is attached to the Animal type's implicit part (Animal).
var speciesTerms = (IEnumerable<TermPart>)speciesField.Terms;
foreach (var speciesTerm in speciesTerms) {
var list = speciesDictionary.ContainsKey(speciesTerm) ? speciesDictionary[speciesTerm] : default(IList<ContentItem>);
if (list == null) {
list = new List<ContentItem>();
speciesDictionary.Add(speciesTerm, list);
}
list.Add(item);
}
}
}
<ul>
#foreach (var speciesTerm in speciesDictionary.Keys) {
var items = speciesDictionary[speciesTerm];
<li>
#speciesTerm.Name
</li>
}
</ul>

Your first error indicates that you are trying to get a property of the ContentItem class which does not exist. This is actually partially correct, because it does exist on the ContentItem, but because you cast it to a ContentItem class, it loses the dynamic properties.
You can fix this by not casting to a ContentItem class, but just to dynamic:
var items = ((IEnumerable<dynamic>)Model.ContentItems);
The second error indicates that you are trying to create a variable while it already exists. This is obvious, because in the top of your .cshtml you already have items defined:
#{
// var items is defined here, you can not redefine it
// as always in C#
var items = ((IEnumerable<ContentItem>)Model.ContentItems);
}
So instead give it a different name in the bottom:
<ul>
#foreach (var speciesTerm in speciesDictionary.Keys) {
// Cannot use 'items' here again
var speciesItems = speciesDictionary[speciesTerm];
<li>
#speciesTerm.Name
</li>
}
</ul>

Related

Razor Pages: Passing query parameters in a link

I tried in the razor page:
<div>
#foreach (var cat in Model.Categories)
{
<a asp-page="/Index?catId=#cat.Id">#cat.Name</a>
}
</div>
And in the cs file:
public void OnGet()
{
CurPage = 1;
CatId = -1;
Search = "";
HasCarousel = false;
Title = "All Products";
var queryParams = Request.Query;
foreach(var qp in queryParams)
{
if (qp.Key == "curPage") CurPage = int.Parse(qp.Value);
if (qp.Key == "catId") CatId = int.Parse(qp.Value);
if (qp.Key == "search") Search = qp.Value;
if (qp.Key == "hasCarousel") HasCarousel = bool.Parse(qp.Value);
}
But when i click the link no query parameter is added to the address and the Request.Query is empty.
What am I doing wrong? Or what is the right way to pass the query parameters to a razor page via a link?
To add query parameters to your link you can use asp-route- in your a tag.
In your case it would look like
<a asp-page="Index" asp-route-catId="#cat.Id">#cat.Name</a>
You're also making receiving the query parameters in your OnGet() harder than it has to be. You can add parameters to your method signature like
OnGet(int catId)
and they will be passed in by the query parameters.

Adding a reusable block of code in Webmatrix

I have created an SQL query which checks if a user owns a record in the database, by checking if the querystring and UserID return a count of 1. This is the code below, and it works absolutely fine:
#{
Layout = "~/_SiteLayout.cshtml";
WebSecurity.RequireAuthenticatedUser();
var db = Database.Open("StayInFlorida");
var rPropertyId = Request.QueryString["PropertyID"];
var rOwnerId = WebSecurity.CurrentUserId;
var auth = "SELECT COUNT (*) FROM PropertyInfo WHERE PropertyID = #0 and OwnerID = #1";
var qauth = db.QueryValue (auth, rPropertyId, rOwnerId);
}
#if(qauth==0){
<div class="container">
<h1>You do not have permission to access this property</h1>
</div>
}
else {
SHOW CONTENT HERE
}
The problem is that I need to apply this check on at least 10 different pages, maybe more in the future? I'm all for using reusable code, but I'm not sure how I can write this once, and reference it on each page that it's needed. I've tried doing this in the code block of an intermediate nested layout page, but I ran into errors with that. Any suggestions as to what would be the best approach? Or am I going to have to copy and paste this to every page?
The "Razor" way is to use a Function (http://www.mikesdotnetting.com/Article/173/The-Difference-Between-#Helpers-and-#Functions-In-WebMatrix).
Add the following to a file called Functions.cshtml in an App_Code folder:
#functions {
public static bool IsUsersProperty(int propertyId, int ownerId)
{
var db = Database.Open("StayInFlorida");
var sql = #"SELECT COUNT (*) FROM PropertyInfo
WHERE PropertyID = #0 and OwnerID = #1";
var result = db.QueryValue (sql, propertyId, ownerId);
return result > 0;
}
}
Then in your page(s):
#{
Layout = "~/_SiteLayout.cshtml";
WebSecurity.RequireAuthenticatedUser();
var propertyId = Request["PropertyID"].AsInt();
var ownerId = WebSecurity.CurrentUserId;
}
#if(!Functions.IsUsersProperty(propertyId, ownerId)){
<div class="container">
<h1>You do not have permission to access this property</h1>
</div>
}
else {
SHOW CONTENT HERE
}

How to show ID field as readonly in Edit Form, of a sharepoint list?

I need to show the ID field in the Edit Form of a sharepoint list.
There is a way to do it ? I tried a calculated field and nothing.
I know that I can see the ID field in the view, and if I show as a Access Mode.
I'm using WSS3.0
You can add the ID field to the form using some JavaScript in a CEWP.
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">
</script>
<script type="text/javascript">
$(function() {
// Get the ID from the query string
var id = getQueryString()["ID"];
// Find the form's main table
var table = $('table.ms-formtable');
// Add a row with the ID in
table.prepend("<tr><td class='ms-formlabel'><h3 class='ms-standardheader'>ID</h3></td>" +
"<td class='ms-formbody'>" + id + " </td></tr>");
})
function getQueryString() {
var assoc = new Array();
var queryString = unescape(location.search.substring(1));
var keyValues = queryString.split('&');
for (var i in keyValues) {
var key = keyValues[i].split('=');
assoc[key[0]] = key[1];
}
return assoc;
}
</script>
There is an alternative method that doesn't use the jQuery library if you prefer to keep things lightweight.
You can do this by creating a custom edit form quite easily. I usually stick it into an HTML table rendered within a webpart. There may be a better way of doing that but it's simple and it works.
The key line you'll want to look at is spFormField.ControlMode. This tells SharePoint how to display the control (Invalid, Display, Edit, New). So what you'll want to do is check if your spField.InternalName == "ID" and if it is, set the ControlMode to be Display.
The rest is just fluff for rendering the rest of the list.
Hope this helps.
HtmlTable hTable = new HtmlTable();
HtmlTableRow hRow = new HtmlTableRow();
HtmlTableCell hCellLabel = new HtmlTableCell();
HtmlTableCell hCellControl = new HtmlTableCell();
SPWeb spWeb = SPContext.Current.Web;
// Get the list we are going to work with
SPList spList = spWeb.Lists["MyList"];
// Loop through the fields
foreach (SPField spField in spList.Fields)
{
// See if this field is not hidden or hide/show based on your own criteria
if (!spField.Hidden && !spField.ReadOnlyField && spField.Type != SPFieldType.Attachments && spField.StaticName != "ContentType")
{
// Create the label field
FieldLabel spLabelField = new FieldLabel();
spLabelField.ControlMode = _view;
spLabelField.ListId = spList.ID;
spLabelField.FieldName = spField.StaticName;
// Create the form field
FormField spFormField = new FormField();
// Begin: this is your solution here.
if (spField.InteralName == "ID")
{ spFormField.ControlMode = SPControlMode.Display; }
else
{ spFormField.ControlMode = _view; }
// End: the end of your solution.
spFormField.ListId = spList.ID;
spFormField.FieldName = spField.InternalName;
// Add the table row
hRow = new HtmlTableRow();
hTable.Rows.Add(hRow);
// Add the cells
hCellLabel = new HtmlTableCell();
hRow.Cells.Add(hCellLabel);
hCellControl = new HtmlTableCell();
hRow.Cells.Add(hCellControl);
// Add the control to the table cells
hCellLabel.Controls.Add(spLabelField);
hCellControl.Controls.Add(spFormField);
// Set the css class of the cell for the SharePoint styles
hCellLabel.Attributes["class"] = "ms-formlabel";
hCellControl.Attributes["class"] = "ms-formbody";
}
}

How to get current Item in Custom Form Action Sharepoint Designer

On custom edit page of list item, I want to do the following
- On clicking Form Action Hyperlink [DataView Control], custom form action will fire to update
a item hidden field [Status].
I already tried the following
- Passing #ID to the work flow but didnt work
- Create a duplicate ID column and updated it with the ID on Item Creation. and then tried to access in "Update Item in" Action but getting "An unexpected error has occurred" while running it.
[Remember i can only use sharepoint designer]
Try to use these javascript functions:
function GetQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
}
function GetCurrentItem() {
var itemId = GetQueryVariable("ID");
try {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
var list = web.get_lists().getByTitle('list-title');
this.currItem = list.getItemById(itemId);
context.load(currItem);
context.executeQueryAsync(Function.createDelegate(this, this.funcSuccess), Function.createDelegate(this, this.funcFailed));
}
catch (e) {
alert(e);
}
}
function funcSuccess() {}
function funcFailed() {}

Programmatically set a TaxonomyField on a list item

The situation:
I have a bunch of Terms in the Term Store and a list that uses them.
A lot of the terms have not been used yet, and are not available yet in the TaxonomyHiddenList.
If they are not there yet they don't have an ID, and I can not add them to a list item.
There is a method GetWSSIdOfTerm on Microsoft.SharePoint.Taxonomy.TaxonomyField that's supposed to return the ID of a term for a specific site.
This gives back IDs if the term has already been used and is present in the TaxonomyHiddenList, but if it's not then 0 is returned.
Is there any way to programmatically add terms to the TaxonomyHiddenList or force it happening?
Don't use
TaxonomyFieldValue tagValue = new TaxonomyFieldValue(termString);
myItem[tagsFieldName] = tagValue;"
because you will have errors when you want to crawl this item.
For setting value in a taxonomy field, you have just to use :
tagsField.SetFieldValue(myItem , myTerm);
myItem.Update();"
Regards
In case of usage
string termString = String.Concat(myTerm.GetDefaultLabel(1033),
TaxonomyField.TaxonomyGuidLabelDelimiter, myTerm.Id);
then during instantiation TaxonomyFieldValue
TaxonomyFieldValue tagValue = new TaxonomyFieldValue(termString);
exception will be thrown with message
Value does not fall within the expected range
You have additionally provide WssId to construct term string like shown below
// We don't know the WssId so default to -1
string termString = String.Concat("-1;#",myTerm.GetDefaultLabel(1033),
TaxonomyField.TaxonomyGuidLabelDelimiter, myTerm.Id);
On MSDN you can find how to create a Term and add it to TermSet. Sample is provided from TermSetItem class description. TermSet should have a method CreateTerm(name, lcid) inherited from TermSetItem. Therefore you can use it in the sample below int catch statement ie:
catch(...)
{
myTerm = termSet.CreateTerm(myTerm, 1030);
termStore.CommitAll();
}
As for assigning term to list, this code should work (i'm not sure about the name of the field "Tags", however it's easy to find out the proper internal name of the taxonomy field):
using (SPSite site = new SPSite("http://myUrl"))
{
using (SPWeb web = site.OpenWeb())
{
string tagsFieldName = "Tags";
string myListName = "MyList";
string myTermName = "myTerm";
SPListItem myItem = web.Lists[myListName].GetItemById(1);
TaxonomyField tagsField = (TaxonomyField) myList.Fields[tagsFieldName];
TaxonomySession session = new TaxonomySession(site);
TermStore termStore = session.TermStores[tagsField.SspId];
TermSet termSet = termStore.GetTermSet(tagsField.TermSetId);
Term myTerm = null;
try
{
myTerm = termSet.Terms[myTermName];
}
catch (ArgumentOutOfRangeException)
{
// ?
}
string termString = String.Concat(myTerm.GetDefaultLabel(1033),
TaxonomyField.TaxonomyGuidLabelDelimiter, myTerm.Id);
if (tagsField.AllowMultipleValues)
{
TaxonomyFieldValueCollection tagsValues = new TaxonomyFieldValueCollection(tagsField);
tagsValues.PopulateFromLabelGuidPairs(
String.Join(TaxonomyField.TaxonomyMultipleTermDelimiter.ToString(),
new[] { termString }));
myItem[tagsFieldName] = tagsValues;
}
else
{
TaxonomyFieldValue tagValue = new TaxonomyFieldValue(termString);
myItem[tagsFieldName] = tagValue;
}
myItem.Update();
}
}

Resources