Obtaining component title from the Tridion broker - tridion-2011

This code works to get content from the broker for all components whos name begins with "MC":
Criteria c1 = new ItemTitleCriteria("MC%", Criteria.Like);
//Create query
Query myQuery = new Query(c1);
String[] itemURIs = myQuery.ExecuteQuery();
ComponentPresentationAssembler cpAssembler = new ComponentPresentationAssembler();
foreach (string componentUri in itemURIs)
{
String content = cpAssembler.GetContent(componentUri, componentTemplateUri);
}
However, I am struggling to find in the api where I can actually access the names (or titles) of each component returned.

I'm not sure if the broker API has such capabilities to retrieve those attributes. You may probably need to use another library to retrieve information from the CMS.
But to answer your question, one way to get the title if to publish it to the brokerDB as part of the content (cpAssembler.GetContent()). Just make sure that you render Component.Title in the component template. Once it's in the DB, you can parse it.
Sample content:
<model id="modelId" title="componentTitle" />
Note: Tridion has its own StackExchange site now, you may get more interaction there. https://tridion.stackexchange.com/

Related

In Meteor, where do I model my business rules?

Beginner question : I've worked through the Try Meteor tutorial. I've got fields in my HTML doc, backed by helper functions that reference collections, and BOOM --> the fields are updated when the data changes in the DB.
With the "Hide completed" checkbox, I've also seen data-binding to a session variable. The state of the checkbox is stored in the Session object by an event handler and BOOM --> the list view is updated "automatically" by its helper when this value changes. It seems a little odd to be assigning to a session object in a single page application.
Through all this, my js assigns nothing in global scope, I've created no objects, and I've mostly seen just pipeline code, getting values from one spot to another. The little conditional logic is sprayed about wherever it is needed.
THE QUESTION... Now I want to construct a model of my business data in javascript, modelling my business rules, and then bind html fields to this model. For example, I want to model a user, giving it an isVeryBusy property, and a rule that sets isVeryBusy=true if noTasks > 5. I want the property and the rule to be isolated in a "pure" business object, away from helpers, events, and the meteor user object. I want these business objects available everywhere, so I could make a restriction, say, to not assign tasks to users who are very busy, enforced on the server. I might also want a display rule to only display the first 100 chars of other peoples tasks if a user isVeryBusy. Where is the right place to create this user object, and how do I bind to it from my HTML?
You can (and probably should) use any package which allows you to attach a Schema to your models.
Have a look at:
https://github.com/aldeed/meteor-collection2
https://github.com/aldeed/meteor-simple-schema
By using a schema you can define fields, which are calculated based on other fields, see the autoValue property: https://github.com/aldeed/meteor-collection2#autovalue
Then you can do something like this:
// Schema definition of User
{
...,
isVeryBusy: {
type: Boolean,
autoValue: function() {
return this.tasks.length > 5;
}
},
...
}
For all your basic questions, I can strongly recommend to read the DiscoverMeteor Book (https://www.discovermeteor.com/). You can read it in like 1-2 days and it will explain all those basic questions in a really comprehensible way.
Best Regards,
There is a very good package to implement the solution you are looking for. It is created by David Burles and it's called "meteor-collection-helper". Here it the atmosphere link:
You should check the link to see the examples presented there but according to the description you could implement some of the functionality you mentioned like this:
// Define the collections
Clients = new Mongo.Collection('clients');
Tasks = new Mongo.Collection('tasks');
// Define the Clients collection helpers
Clients.helpers({
isVeryBusy: function(){
return this.tasks.length > 5;
}
});
// Now we can call it either on the client or on the server
if (Meteor.isClient){
var client = Clients.findOne({_id: 123});
if ( client.isVeryBusy() ) runSomeCode();
}
// Of course you can use them inside a Meteor Method.
Meteor.methods({
addTaskToClient: function(id, task){
var client = Clients.findOne({_id: id});
if (!client.isVeryBusy()){
task._client = id;
Tasks.insert(task, function(err, _id){
Clients.update({_id: client._id}, { $addToSet: { tasks: _id } });
});
}
}
});
// You can also refer to other collections inside the helpers
Tasks.helpers({
client: function(){
return Clients.findOne({_id: this._client});
}
});
You can see that inside the helper the context is the document transformed with all the methods you provided. Since Collections are ussually available to both the client and the server, you can access this functionality everywhere.
I hope this helps.

WebApi OData formatter doesn't work for child elements

Following code converts the ViewModel query to model and then converts the returned result back to ViewModel as PageResult. All this works fine but when I try to use include as part of my default query(or even with the latest version as part of querycontext) then OData formatter plays funny and doesn't include child elements. I have debugged and confirmed that it actually contains child elements. This only happens for controllers that I extended from ODataController(so basically for the ones that are extended from ApiController all works fine but i need results in OData format).
Please note that I have also tried with the latest nightly build(Microsoft.Data.OData 5.5.0.0) and still it doesn't work for me.
Any help would highly be appreciated.
public class ProductsController : ODataController
{
APPContext context = new APPContext();
public PageResult<ProductViewModel> Get(ODataQueryOptions QueryOptions)
{
EdmModel model = new EdmModel();
ODataQueryContext queryContext = new ODataQueryContext(model.GetEdmModel(), typeof(Product));
var mappedQuery = new ODataQueryOptions(queryContext, QueryOptions.Request);
var results = new List<ProductViewModel>();
foreach (var result in mappedQuery.ApplyTo(this.context.Serials.Include("Status").Include("Category")))
{
AutoMapper.Mapper.CreateMap(result.GetType(), typeof(ProductViewModel));
results.Add(AutoMapper.Mapper.Map<ProductViewModel>(result));
}
PageResult<ProductViewModel> pr = new PageResult<ProductViewModel>(results.AsEnumerable<ProductViewModel>(), mappedQuery.Request.GetNextPageLink(), mappedQuery.Request.GetInlineCount());
return pr;
}
}
In OData related entities are represented as navigation links. So, if you have a customers feed, the related orders for each customer will not be part of the customers feed. Instead, they would be represented as navigation links. You can explicitly tell the OData service to expand the related entities using the $expand query option. So, if you want the related orders for each customer to be expanded, you should ask for the url ~/Customers?$expand=Orders.

reading related data after a selection of a foreign key - MVC3 and EF4

I am new to MVC and EF and I have a question.
I have built a site with models views controllers etc.
On an edit view for a Case (pretty big model so I won't post it here) I have a FK to a Customer model using CustomerID. When a user selects a customer id from a drop down list, I would like to display CustomerName, CustomerPhone etc after the selection of the ID. I think I might need to do a post back for this to work?
Also, do I need to Include the related entities as part of the initial data "get"? I have read some detail on that but I dont fully understand how that needs to work.
Please let me know if I should post more info. Thanks!
Here is my ActionResult for Edit
public ActionResult Edit(int id)
{
Cases cases = db.Cases.Find(id);
//related data needs to loaded to show related data fields
//include related data entities
var v = db.Cases.Include("Customers");
ViewBag.TechnicianID = new SelectList(db.Technicians, "TechnicianID", "LastName", cases.TechnicianID);
ViewBag.BranchID = new SelectList(db.Branches, "BranchID", "BranchName", cases.BranchID);
ViewBag.EngineModelID = new SelectList(db.EngineModels, "EngineModelID", "EngineModelName", cases.EngineModelID);
ViewBag.CaseCategoryID = new SelectList(db.CaseCategories, "CaseCategoryID", "CategoryName",cases.CaseCategoryID);
ViewBag.Qualified = new SelectList(new[] { "YES", "NO", "PARTIALLY" });
ViewBag.CaseStatus = new SelectList(new[] { "OPEN/IN PROCESS", "CLOSED" });
return View(cases);
}
The line
var v = db.Cases.Include("Customers")
is what I am trying to use to load related customer data and then show in my edit view like this:
#Html.EditorFor(model => model.Customer.CustomerName)
Well it depends on what you are trying to do. You could include a model which holds all the required data and send it with every call on that page (initial empty ofcourse)
Once you selected the customer, do post-back and send the customerId to your application and return the same page with the desired model.
You could do that via AJAX too.
Also, do I need to Include the related entities as part of the initial data "get"?
Not sure if I understand what you are trying to say. You mean that you think you would have to send all customer's data down to the page and select the related data on client side?

MVC3 -- Adding additional items to List<> with Jquery

I have a view model that looks like this:
HomeViewModel hvm = new HomeViewModel();
hvm.Applicant = new Person();
hvm.Applicant.Residences = new List<Residence>();
hvm.Applicant.Residences.Add(new Residence() { Type = "Current" });
In my .cshtml page, I have:
<label>Street # *:</label> #Html.TextBoxFor(m => m.Applicant.Residences[0].StreetNumber)
And so on and so forth for my properties in my Residence model. However, I want the user to be able to add multiple residences(previous, secondary, other, etc). I can add the necessary form fields via jquery, however, since the model doesn't know about the new list items, I get an error about null objects. The front end may be adding numerous residences via jquery.
This is a surprisingly complex topic. Check out the blog series starting with http://ivanz.com/2011/06/16/editing-variable-length-reorderable-collections-in-asp-net-mvc-part-1/
Try this: http://archive.plugins.jquery.com/project/jquery-dynamic-form
View demo here: http://sroucheray.org/blog/jquery-dynamic-form/

How do I display customer specific information avoiding using xslt?

My place of work currently maintains a website for several customers which is written using classic asp. Each customer requires specific parts of the website to be written specifically to them.
For example, customer A requires an Address to be input, displayed and stored in the following format:
Address Line 1
Address Line 2
Address Line 3
Address Line 4
Address Line 5
Postcode
whereas customer B requires the Address to be input, displayed and stored as:
Street
Town
City
Postcode
and so forth...
Therefore, my place of work took the path of storing the data as xml in the database and using xsl (of which I currently know little) to transform the data to html.
So if we require information from the user via a html form, the xml is transformed using xsl. The user then enters the information and submits the data via the form. An asp page is then used to validate the data. This asp page is specific to the xsl page used to display the form. Therefore, we are now in a postion where for each customer we have many xsl pages and many customer specific asp pages (where much of the code is duplicated).
I have been asked to move the site over to asp.net mvc3 and to remove much of the duplication and was wondering what would be the best way to cater for this customer specific field functionality. My preference would be to keep the data stored as xml as the database layer is accessed using com components which I would like to reuse without changing.
I have read that I could keep the xsl pages and develop an xslt view engine to display the html. However, I am not sure how I would validate the data when the user submits the form?
What would be the best way to display customer specific fields if I was to remove the xsl completely? Or would I have to have customer specific views and view models?
Any thoughts would be much appreciated.
If you really want to use MVC's built in validation / model functionality I think your best bet would be to use the XmlSerializer or use DataContracts to develop something that serializes to and from your XML (once its retrieved from the COM objects, so you don't need to re-code those), then you can use those classes as Models for MVC and use the standard data annotations for taking advantage of the richer MVC model functionality and skip the XSL step entirely.
To couple this with a custom specific view, what I typically do is override the default view engine to have one that actually will try names that are more specific to the customer/object and then fallback to a general one.
This view engine would allow you to pass a view to pass a view name (ie. FallbackViewEngine.BuildViewName("General", "Customer Name") and it would look for "General.Customer Name.cshtml" first and then "General.cshtml" as a fallback. This way you can actually use customer specific views in your view folder.
public class FallbackViewEngine : RazorViewEngine
{
const string NameSeparator = "==";
const string FileSeparator = ".";
public static string BuildViewName(string root, params string[] fallbackList)
{
if (string.IsNullOrWhiteSpace(root)) throw new ArgumentNullException("root");
if (fallbackList == null) throw new ArgumentNullException("fallbackList");
var sb = new StringBuilder(root);
foreach (var s in fallbackList)
{
if (string.IsNullOrWhiteSpace(s)) continue;
sb.Append(NameSeparator);
sb.Append(s);
}
return sb.ToString();
}
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (string.IsNullOrWhiteSpace(viewName)) throw new ArgumentNullException("viewName");
var names = viewName.Split(new string[] {NameSeparator}, StringSplitOptions.None);
var searched = new List<string>();
//iterate from specific to general
for (var i = names.Length; i >= 1; i--)
{
var result = base.FindView(controllerContext, string.Join(FileSeparator, names, 0, i), masterName, useCache);
if (result.View != null)
{
return result;
}
else
{
searched.AddRange(result.SearchedLocations);
}
}
return new ViewEngineResult(searched);
}
}

Resources