Orchard Projections & Collapse Accordion - asp.net-mvc

I've created a custom content type and a Projection page of them, but cannot shoehorn all the various Parts and Fields into a Bootstrap Collapse.
I am encountering two problems: I have too many characters in the Layout's Property Rewrite Results; or if I add, for example, #Display(Model.ContentItem.FunOpp.FunTitle.Value) to the custom .cshtml shape, I get a 'Orchard.ContentManagement.ContentItem' does not contain a definition for 'FunOpp' error; or something similar depending upon my layout.
The custom content type definition is:
Fields:
Sponsor (Text Field)
​Funding Opportunity (Link Field)
​Funding Title (Text Field)
Closing/Due Date (Text Field)
Funding Opportunity
Number (Text Field)
Accordion Collapse Number (Text Field)
Parts:
Body
I need the Funding Title to be the Accordion-Heading; and all the remaining Fields & Parts to be the Accordion-Inner.
There is a lot of content, and Bootstrap's Collapse requires a lot of markup, so obviously I am getting the "too many characters" error if I go the Token/Rewrite Results route for the Accordion-Inner.
Yet I don't know enough MVC/Razor to determine why I'm getting the Model.ContentItem errors.
Any help would be appreciated, be it somehow combining the Tokens in the Rewrite Output to save characters; or a way to display the various #Model.ContentItem.FunOpp.xxx.Value

I don't really understand much of the plumbing but Content Item is a class, but also a dynamic object. You are currently trying to get FunOpp from the class, which doesn't have such a property, only the dynamic object content item does. So you will need to do...
#{
dynamic item = Model.ContentItem;
var funtitle = item.FunOpp.FunTitle.Value;
}
Something along those lines

Enable the Module "Shape Tracer" to see the exact structure of the Model. This is the best way to figure out what orchard is doing under the hood.

Related

How to use same scripts in views

I have a view for creating an entity by filling a form. That form contains several inputs and 2 datatables table. i write a considerable amount of JavaScript code for initialization and validation of the inputs. For editing the entity, i need the 95% of inputs and JavaScript codes.
First, I tried to move the common codes to a partial view but some of them worked and some of it didn't work. For example the tables not initialized.
As a second approach, I can also write a lot of if-else to check the current page (between Create and Edit) and do proper action.
How can i have two views and common codes in both? Is there a better or functional approach?
save your javascript code as js file. Drag and drop its link where you want to use it :)
You can use the same view for Create and edit functionality.
And regarding the inputs, you can take one property in the model which will indicate whether to show or not to show that input on UI.
Model:
For eg. Public string displayInput=[none/block]
view:
You need to set the value of displayInput field properly when you want to show all fields and when you want to hide some fields.

Can Orbeon controls have multiple values?

I think the answer is no, but the question has been put to me so I'd like to confirm. My understanding is that any custom XBL control that I create for use in Form Builder can have one and only one value. Is this correct?
I have always assumed this because the control name is then used in the data instance as the name of the node which contains the the value.
This question comes from the desire to have reusable components with multiple values, for example, an Address control so that addresses can be recorded consistently and the same set of fields does not need to be added many times. Orbeon does have some support for this in the form of Section Templates but because the control names stay the same in each instance of a Section Template this does not work well with our design.
The best idea I've had is that a custom control which records multiple values could encode all the values into a single text string for example in JSON. Of course, this is not ideal.
Are there any other options?
It is possible for controls to have multiple values. When that happens the values are typically stored in nested elements. I.e. a control could bound to an element <address>, and could create nested elements <street>, <city>,<country>, etc to store the different parts of the address.
In practice, you can look at how this is done in the Image Annotation annotation control (see wpaint.xbl), which creates nested elements <image> and <annotation>, leveraging the xxbl:mirror="true" functionality.

Orchard CMS conditionally hide widget and suppress zone

I am trying to conditionally suppress a widget from its driver. I basically have logic that if met, should display the widget and if not, should suppress it. The widget loads properties from the current page content item, and based on some properties should display or hide. I've got all the logic working, the only part left is suppressing the actual output.
I've tried returning null from the driver, however this simply outputs an empty widget (with its wrapper). How do I completely remove the widget from view?
Finally, the zone that this widget is placed in should suppress if none of the conditional widgets display.
Is this type of flexibility possible in Orchard? Preferably from my custom module not my theme, I'm trying to separate functionality from styling.
EDIT:
Here is the context of my situation and what I am trying to accomplish. I'm sure there is a much cleaner way to do this within Orchard than how I have naively designed it the first go-around: My client's copywriters tag pages as they see fit (using the Tags module/part). I have created 2 custom content types, "Testimonials" and "Offers", both with tags themselves among other properties [these are managed by a different team of copywriters].
On most "inner pages" of the website (I'm using a layer to determine the appropriate pages), the page's sidebar gets a "Testimonial" widget and a "Offer" widget. These widgets both operate the same, although independently of each other:
They grab the tags of the current page, then pull a random [Testimonial|Offer] that has any matching tags as well. There are 4 cases that can happen given any inner page: a testimonial is displayed and the offer is hidden (testimonial tag matched, offer tag didn't), the testimonial is hidden and the offer is displayed, both the testimonial and offer displays, and finally neither displays. The first 3 use cases are working great, the 4th is what I'm having difficulty with, as the sidebar [zone] still displays even if both widgets do not (returning null from their respective drivers).
A bit of context about widgets: widgets are supposed to be pieces of contents that are visible on some or all pages of the site, and that provide information that is not directly related to the main content item on the page (if there is such a thing).
As a consequence, what you are describing should not be implemented as widgets (all that you had to do to make it work attests to that further), because they are really part of the content item. Instead, you should have implemented a part or a field. You can then simply place the shape for this part of field, using placement, by specifying a top-level zone: <place the_shape_name="/the_zone_where_you_want_it:1"/>
Unfortunately I've had to use a bit of a hack so that I could move on with the project as I'm under an aggressive deadline, but if there is a better method and/or solution I'll test as I get the chance and mark as the answer.
To get it to work, I overwrote the Widget.Wrapper.cshtml file within my theme. There, I assigned a variable to the Display(Model.Child) call, and if the result is an empty string simply return. This removes any empty widget wrapping tags. (I personally feel Orchard should behave this way by default):
var child = Display(Model.Child);
// -- NOTE: shape tracing breaks this logic!
if (string.IsNullOrWhiteSpace(child.ToString())) {
return;
}
Then simply replace the #Display(Model.Child) between the header and footer with #(child)
I then added the following method to my Layout.cshtml file.
Func<dynamic, IHtmlString> CollapsableZone = x =>
{
var display = Display(x);
string zoneName = x.ZoneName;
if (string.Equals(display.ToString(), string.Format("<div class=\"zone zone-{0}\"></div>", zoneName.HtmlClassify()), StringComparison.CurrentCultureIgnoreCase))
{
return new HtmlString(string.Empty);
}
return display;
};
Simple function that assigns the display call to a variable, checks if it is an empty zone tag, and returns. I then create variables for each zone assigned to the value of the function above. I replace all the #if (Model.ZoneName != null) with #if (!string.IsNullOrWhiteSpace(zoneVariable)), and replace the calls to #Zone(Model.ZoneName) with #(zoneVariable).
This is working for the time being. It is quite a hack and brittle solution but I've had to move on to other things.

ASP.NET MVC DateTime format dynamically

I am looking for a way to dynamically specify the format of my model DateTime fields in the view. I need these to be editable (meaning I want changes to them to be properly bound to model on postback). I am not worried about validation as I will be using a jquery datepicker control on the resulting textboxes.
So far all I have found is a way of setting the format in data annotations in the model - which is way too static and restricting (unless there is also a way to modify data annotations at runtime?). Have also found guides for making templates for DateTime, but that is also static. Found some ways to format the fields in the view for "display only" requirements that won't post back changes.
So far the only thing I have come up is having a separate string field for each DateTime field in all my models, do conversion in controllers manually before displaying only the string fields, and then convert them back. Before I embark on his messy approach, does anyone have any suggestions for an easier/cleaner way?
You could technically write your own Annotation that will give you the dynamic format depending on your wants.
These are evaluated at runtime so depending on what you want to return you can do it then.
I am currently using attributes to return very specific data for specific uses.

ASP.NET MVC - problem logically undertanding how to structure a report section

The problem: Using ASp.NET MVC for reporting.
Given:
1. A report that is tabular in output, so it can easiyl be represented by a class (static field list).
2. A filter mask containing halfa dozen or more possible conditions to apply to the data.
How is the approach for the MVC file layout?
I would say one controller for the complete report.
But how does the model look? One property with all the filter conditiond (or: a property per filter condition), one property with an enumeration of results?
I would also love to do a redirect when the search parameters change and would love to see the parameters as parameters (i.e. the URL ending in /Reports/Assets?From=...&To=...) so users can bookmark a specific favourite report or email the URL around.
How to do? I have a lon gbackground in ASP.NET, but MVC somehow eludes me ;)
Thoughts rather than answers:
In MVC the ideal is to send to the view pretty much just the data to be rendered by the view, if that's something from your base model then that works nicely if its something specific to the view (or a group of views) then that's what you do.
In so far as possible you don't want decision logic in your view - and if there is decision logic that really should be concerned just with how to render a specific element, so the simplest model for your report is just the rows of data (something IEnumerable) and the view is just a foreach.
That then makes the controller's job one of building the query and passing it (or the results, depending on what works) to the view.
Initially I considered that you could instead pass the unfiltered data and a filter to the view and then you are still doing a foreach but to the raw data with the filter attached... but having worked my way through this slowly that's nowhere near as neat.
Becuase all the filter logic is in the controller (the view just outputs the query result) you can pretty much do what you want with the URLs - your view is either report specific or you can have a more generic view and pass in the column type/heading/format data as well as the row data others should comment on the advisability of that...

Resources