dynamically add a durandal widget - widget

What is the process of adding a widget to a page dynamically? Essentially I have an "Add Widget" button on a view which is hooked up to a function addWidget() in the viewmodel. Basically, when someone hit's the button, I want to dynamically create an instance of a durandal widget and add it to the DOM. My code looks like this:
var addWidget = function () {
var parent = $('<div></div>')
.attr('data-bind', 'widget: { kind:\'myWidget\'}')
.appendTo($('#dashboardContent'))
.get(0);
return widget.create(parent, { id: 'Hello World' });
}
I can see in the browser developer tools that the widget HTML (view) is added to the DOM, but it's not rendering the widget, and activate is not being called on the widget.
What am I missing?

From the looks of it you are trying to use jQuery to add the widget to the DOM. Just thinking out loud the problems are that A: jQuery has no idea what activate is (that is handled by Durandal's router) and B: Nothing will get bound properly. If you are trying to add widgets, why not create an observableArray that contains widgets and just add them into there? That may sound a bit silly, and I am not sure the best way to approach it, but basically it could look like this
In your view model -
var myWidgets = observableArray();
myWidgets.push(someObjectsToComposeTheWidget);
And in your view -
<ul data-bind="foreach: myWidgets">
<li data-bind="widget: {kind:'yourWidget', items: somethingGoesHere, headerProperty:'name'}">/div>
<ul>
This will allow you to dynamically add and display the widgets without having to get messy and use jQuery to display things.

Related

Orchard - Add an additional shape name (i.e. an alternate) for the main List shape

Introduce the Problem
I would like to profoundly modify the layout of the Orchard CMS Tags list.
Here is an example page with Shape Tracing enabled.
The only alternate that it suggests for the List shape is ~/Themes/TheThemeMachine/Views/List.cshtml, because the page is rendering the default List shape. I would like to have other alternates that are specific to the page.
After reading Orchard list customization, I have been able to implement the default List.cshtml in razor. What I would like to do, though, is to add another alternate, such as ~/Themes/TheThemeMachine/Views/Parts.Tags.List.cshtml instead of implementing the default List.cshtml template.
The problem seems to be that the page is rendering the generic List shape.
In contrast, the blog post list page is rendering a Parts_Blogs_BlogPost_List shape, which means that a ~/Themes/TheThemeMachine/Views/Parts.Blogs.BlogPost.List.cshtml is available.
Search and Research
All quotes below are from the Orchard list customization blog post, which explains how to add a list item alternate (whereas I would like to add a list alternate).
What we really want is an alternate template... aptly called Shape
Alternates... [so] enable Shape Tracing... and select a post in the list...
[you will see that] we already have some possible alternates.
My example page also has some possible alternates for the List Content. Cool.
we need to somehow get into list rendering... [t]he default is defined
in code... [which] can be override by a new [cshtml] template in our
theme.
Okay. That makes sense. We can override the list rendering.
As Shape Tracing can show, we can override the list rendering for a
blog by creating a Parts.Blog.BlogPost.List.cshtml template.
This works for alog but not for the blog Tag page (example page). You see, the blog displays a **Parts_Blogs_BlogPost_List shape and suggests an appropriate alternate but the blog tags page displays the default List shape with no alternates other than List.cshtml.
Blog Page with alternates galore
Blog Tags Page with one alternate List.cshtml
So, I created a List.cshtml not a Parts.Blog.BlogPost.List.cshtml template, and save it in my theme's Views directory. (One problem here is that, once we get it working, we will b overriding the default List rendering.)
Then I add the Razor code (copy and pasted from Bertrand's post) to override the default rendering for Lists. When I refresh the site, the browser renders a blank page. It isn't working. Here's the code:
This Does NOT Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
var count = items.Count;
var listTag = Tag(list, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
As a trouble shooting step, I replace the List.cshtml with <p>Hello world.</p>. Orchard renders the markup as expected. So, something is incompatible between the Razor code from Bertrand's blog and the Tags List.
To find out what exactly is incompatible, I try Betrand's code one line at time to see where it breaks (yup, VS would be better than WM here). At each change, I restart WebMatrix and view the results. This is the minimal code that breaks it.
The Culprit
#using Orchard.DisplayManagement.Shapes;
#{
var list = Model.ContentItems;
var items = list.Items;
}
list.Items isn't appropriate here. So I comment it out again and run the <p>Hello World</p> version again. Also, Shape Tracing reveals that on my Tags/tagname page, the Content Zone is now rendering the List twice. Is that normal?
As another step, I replace Model.ContentItems just with Model. It works. It seems that, to override the List.cshtml template, we cannot use the ContentItems property of Model. Here is the new, working code:
This Does Work in List.cshtml
#using Orchard.DisplayManagement.Shapes;
#{
//var list = Model.ContentItems;
//var items = list.Items;
var items = Model.Items;
var count = items.Count;
//var listTag = Tag(list, "ul");
var listTag = Tag(Model, "ul");
listTag.AddCssClass("content-items");
listTag.AddCssClass("blog-posts");
var index = 0;
}
#listTag.StartElement
#foreach (var item in items) {
var itemTag = Tag(item, "li");
if (index == 0) {
itemTag.AddCssClass("first");
}
else if (index == count - 1) {
itemTag.AddCssClass("last");
}
#itemTag.StartElement
#Display(item)
#itemTag.EndElement
++index;
}
#listTag.EndElement
Onward through the article.
So far so good, we have effectively taken over the rendering of the
list, but the actual HTML [will] be... identical to what we had before
[except for] the implementation.
Okay. I'm following. We want to modify the rendering not just re-implement it.
Alternates are a collection of strings that describe additional shape
names for the current shape... in the Metadata.Alternates property of any shape.
Gotcha. Now, why doesn't the Tags/tagname page show an alternate other than just List.cshtml for the rendering of the List shape?
All we need to do is add to this list [of alternates]... [and make sure] to respect the lifecycle...
Great. Maybe we can we add another alternate for the List shape on the Tags/tagname page. But, doing that is different from what Betrand is explaining. While Betrand's blog post is excellent, it is explaining how to add an alternate for an item, whereas I would like to add an alternate for the list.
The List.cshtml template is where I would add an alternate for a List Item as follows:
ShapeMetadata metadata = item.Metadata;
string alternate = metadata.Type + "_" +
metadata.DisplayType + "__" +
item.ContentItem.ContentType +
"_First";
metadata.OnDisplaying(ctx => {
metadata.Alternates.Add(alternate);
});
So that...
[t]he list of alternates from Shape Tracing now contains a new item.
Where and how, though, would I add an alternate for the List shape? Bertrand has recommended to check out the Shape Table Providers blog post for this. The quotes below are from that post.
But what if you want to change another shape template for specific
pages, for example the main Content shape on the home page?
This looks like a fit, because my example is the main List shape on the tags page. To do this we...
... handle an event that is triggered every time a shape named "Content"
[in our case "List"] is about to be displayed. [It] is implemented in a shape table provider which is where you do all shape related site-wide operations.
Great! Here is my implementation for adding another template for the main List shape.
TheThemeMachine > ListShapeProvider.cs
namespace Themes.TheThemeMachine
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break(); // break not hit
builder.Describe("List").OnDisplaying(displaying => {
// do stuff to the shape
displaying.ShapeMetadata.Alternates.Add("Tags__List");
});
}
}
}
The above builds and runs but does not hit the breakpoint nor add an alternate for the List shape on the /tags page. So I looked into the Orchard.Azure.MediaServices module and its CloudVideoPlayerShape which implements IShapeTableProvider. Its breakpoint does get hit. How is my code for ListShapeProvider fundamentally different than the code for the CloudVideoPlayerShape?
Also, I installed the Orchard.Themes.CustomLayoutMachine.1.0.nupkg as suggested in Bertrand's blog post. It unfortunately no longer contains an implementation of IShapeTableProvider.
I have also looked at this szmyd post, which does not explain where to put the IShapeTableProvider code.
Further, I installed the Contoso theme from the Orchard Gallery. It works and builds after adding a reference to Microsoft.CSharp. It also includes an implementation of the IShapeTableProvider. Hooray! Comparing its ContentShapeProvider with my ListShapeProvider reveals a subtle but important difference:
Contoso.csproj
<ItemGroup>
<Compile Include="Code\ContentShapeProvider.cs" />
</ItemGroup>
My implementation didn't include the .cs file in the compilation, because my theme has neither a .csproj nor a App_Code folder. So, I recreated my theme with the following code generation:
orchard.exe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
feature enable Orchard.DesignerTools
When adding the ListShapeProvider.cs file, Visual Studio automatically added a ItemGroup/Compile entry for the file, which included the code in compilation. Hooray!
These two posts will help.
Shape Shifting
List Customization
Here are steps of my own minimum solution.
Download and unzip Orchard.Source.1.8.zip.
Open "\Downloads\Orchard.Source.1.8\src\Orchard.sln" in Visual Studio.
Build the solution to create orchard.exe.
Generate a new theme with orchard.exe. Use CreateProject:true because you will need a csproj to include your .cs file.
orchard.exe
setup /SiteName:SITE /AdminUsername:ME /AdminPassword:PWD /DatabaseProvider:SqlCe
feature enable Orchard.CodeGeneration
codegen theme My.FirstTheme /CreateProject:true
theme enable My.FirstTheme
In VS, add a ListShapeProvier.cs file to the root (or any folder) in your theme.
Add the following code to ListShapeProvider.cs.
namespace My.FirstTheme
{
using Orchard.DisplayManagement.Descriptors;
public class ListShapeProvider : IShapeTableProvider
{
public void Discover(ShapeTableBuilder builder)
{
System.Diagnostics.Debugger.Break();
// implementation here
}
}
}
Build the solution.
Run Orchard.Web.
Visual Studio will break at System.Diagnostics.Debugger.Break(). If it doesn't, go to the Orchard Dashboard and make My.FirstTheme the Current Theme.
Now read Shape Shifting to implement public void Discover(ShapeTableBuilder builder).
This post should give you a full response: http://weblogs.asp.net/bleroy/archive/2011/05/23/orchard-list-customization-first-item-template.aspx

in igCombo - How to display in the combo's input the selectedItem's tepmlate

I have an igCombo in durandal project. I load the igCombo through the date-bind property at the dom. I created an itemTemplate for the select element options. I want that where I select any item, the combo's input will show the selectedItem template. Here is my code, but it doesn't work well; it shows in the inpute the follow thing:
[object object]
here is my code:
<span id="combo" data-bind="igCombo: { dataSource: data, textKey: 'name',
valueKey: 'id', width: '400px',
itemTemplate: '${name} | ${id}',
allowCustomValue: true,
selectionChanged: function (evt, ui) {
var concatenatedValue = ui.items.template
ui.owner.text(concatenatedValue);}
}">
</span>
(Please don't answer me that I can simply write in the selectionChanged function the sane piece of code that I wrote in the itemTemplate property, becouse now it is small piece of code, but when it will be longer code- it is not nice to write it twice!!!)
can you help me?
I could try to explain why the combo input would not intentionally use the itemTemplate - the template is meant to be mostly rich HTML content (images, links and whatnot as in this sample http://www.infragistics.com/products/jquery/sample/combo-box/templating) and you can't put that in an input field.
However, in your case you are just using text so it is doable - first the ui.items provided to the event (as the name suggests) is a collection, so take the first one and the items don't have template property unless that is part of your model that I can't see.
Like other Ignite UI controls, the Combo uses the Templating Engine and so can you! Take the itemTemplate from the control and the item from the data source like in this snippet:
function (evt, ui) {
var templatedValue = $.ig.tmpl(ui.owner.options.itemTemplate, ui.owner.options.dataSource[ui.items[0].index]);
ui.owner.text(templatedValue);
}
JSFiddle: http://jsfiddle.net/damyanpetev/tB7Ds/
The templating API is much like the old jQUery templating if you are familiar with that - taking a template and then data object.Using the values from the control itself means you can make them as complicated as you want and write them in one place only, this code doesn't need to change at all.

How to capture a click event on a link inside a HTML widget in GWT?

I´m evaluating GWT as one of the alternatives to develop AJAX applications for my future projects. Untill now it is as good as it gets, but now I´m stuck looking for a way to capture a click on a tag inside HTML widget. I want to write links inside the HTML but I want to process the clicks in my application, withou reloading the page. Imagine I have the following HTML:
<p>GWT is a great tool and I think it will be my preferred tool to develop web applications. To check out my samples <a id='mylink'>click here</a></p>
I want to capture the click over the "click here" part of the text. What I´ve done so far is to try to attach the id "mylink" to some sort of clickable widget and process the click with a ClickHandler for that widget, but nothing is working.
Is there a way to do that? By the way, I know very little about Javascript.
Thank you in advance.
You can also do it like this:
Anchor.wrap(DOM.getElementById("mylink")).addClickHandler(yourClickHandler);
DOM class is com.google.gwt.user.client.DOM.
Edit after comments.
OK, the method works for elements out of GWT widgets (element comes with HTML file). If you need to generate it in GWT code then you can add link element separately. But it won't work if your content goes for instance from DB.
HTMLPanel html = new HTMLPanel("GWT is a great tool and I think it will be my preferred tool to develop web applications. To check out my samples ");`
Anchor a = new Anchor("click here");
a.addClickHandler(yourClickHandler);
html.add(a);
If it is fully dynamic I don't have an idea at this point. I was trying with HTML() widget, where you can plug your click handler, but I couldn't find a right way to determine whether the click was in A element. Strange.
The final approach (I hope)
This one should work finally. And I think this is the way it should be done, especially that it allows any structure of the HTML. The are two ways:
1. Convert links within HTMLPanel
This one will find all A elements and convert them into Anchors. It ignores href attribute, but you can add it easily :)
HTMLPanel html = new HTMLPanel("<p>Multilink example 2: <a>link1</a> and <a>link2</a></p>");
NodeList<Element> anchors = html.getElement().getElementsByTagName("a");
for ( int i = 0 ; i < anchors.getLength() ; i++ ) {
Element a = anchors.getItem(i);
Anchor link = new Anchor(a.getInnerHTML());
link.addClickHandler(...);
html.addAndReplaceElement(link, a);
}
2. Insert links into prepared spots
Just insert placeholders, where the widgets should be inserted. You could also use the addAndReplaceElement() method but with string ID.
Anchor a1 = new Anchor("a1");
a1.addClickHandler(...);
Anchor a2 = new Anchor("a2");
a2.addClickHandler(...);
HTMLPanel html = new HTMLPanel("<p>Multilink example: <span id='a1'></span> and <span id='a2'></span></p>");
html.add(a1, "a1");
html.add(a2, "a2");
Try something like this.
For your web page, you can use UiBinder:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:HTMLPanel ui:field="panel">
<p>
GWT is a great tool and I think it will be my preferred tool to
develop web applications. To check out my samples
<g:Anchor ui:field="myLink" text="click here" />
</p>
</g:HTMLPanel>
</ui:UiBinder>
Notice that I've replaced your tag with an Anchor widget. There is also a Hyperlink widget, which has hooks into the history system.
The Anchor has a id of "myLink", which is used in the GWT companion to the XML file:
public class So extends Composite {
private static SoUiBinder uiBinder = GWT.create(SoUiBinder.class);
interface SoUiBinder extends UiBinder<Widget, So> {
}
#UiField
Anchor myLink;
public So() {
initWidget(uiBinder.createAndBindUi(this));
myLink.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.log("caught the click");
}
});
}
}
I've added a ClickHandler that captures and acts on the click event.
The main program is simple:
public class SOverflow implements EntryPoint {
public void onModuleLoad() {
RootLayoutPanel.get().add(new So());
}
}
Run this after and a webpage appears with the text and hyperlink. Click on it and "caught the click" appears in the console window (I'm using Eclipse).
I hope this is what you're after. If not exactly, it might at least give you some ideas of how to attack your problem.

How to make tabs on the web page?

How to make tabs on the web page so that when click is performed on the tab, the tab gets css changed, but on the click page is also reloaded and the css is back to original.
dont use the jquery :D
all of what you needs a container, a contained data in a varable and the tabs
the container is the victim of the css changes.
the tabs will trigger the changing process.
if you have a static content, you can write this into a string, and simply load it from thiss.
if you have a dinamically generated content, you need to create ajax request to get the fresh content, and then store it in the same string waiting for load.
with the tabs you sould create a general functionusable for content loading.
function load(data) {
document.getElementById("victim").innerHTML = data;
}
function changeCss(element) {
//redoing all changes
document.getElementById("tab1").style.background="#fff";
document.getElementById("tab2").style.background="#fff";
element.style.background = "#f0f";
}
with static content the triggers:
document.getElementById("tab1").onclick = function() {load("static data 1");changeCss(document.getElementById("tab1"))};
document.getElementById("tab2").onclick = function() {load("static data 2");changeCss(document.getElementById("tab2"))};
if you want to change the css, you need another function which do the changes.
i tell you dont use the jquery because you will not know what are you doing.
but thiss whole code can be replaced by jquery like this:
$("tab1").click(function(e) {
$("#tab1 | #tab2").each(function() {
$(this).css("background","#fff"); });
$(this).css("background","#00f");
$("#victim").append("static content 1");
});
$("tab12click(function(e) {
$("#tab1 | #tab2").each(function() {
$(this).css("background","#fff"); });
$(this).css("background","#00f");
$("#victim").append("static content 2");
});
if you know how javascript works then there is noting wrong with the jquery, but i see there is more and more people who just want to do their website very fast and simple, but not knowing what are they doing and running into the same problem again and again.
Jquery UI Tabs:
http://jqueryui.com/demos/tabs/
Have a <A href tag around the "tab" and use onClick to fire some Javascript that changes the CSS.
If you do not want use Jquery for creating of UI tabs, please see my cross-browser JavaScript code: GitHub.
You can use different ways to create tabs and tab content.
Tab content can added only when tab gets focus.
You can remember selected tab. Selected tab opens immediatelly after opening of the page.
You can create tabs inside tab.
Custom background of the tab is available.
Example: Tabs

Integrating a GWT Dialog into an existing HTML application

I have a situation where I need to integrate a gwt dialog (which to the best of my understanding is implemented as a div with z-index manipulation) into an existing html page.
There are two scenarios:
1. Which is the preferrable and more complicated is where i give the host html page another page which they embed as an iframe and I work my magic through there (maybe connect somehow to the parent window and plant my dialog I'm not sure).
2. Where I have limited access to the html page and I plant some code there which will load my dialog box.
Any ideas or thoughts on how I can implement these?
I've been working for a few months now with GWT and have found it quite nice although I have stayed far far away from the whole HTML area and until now all my work has been done strictly inside my java classes.
Thanks for any ideas and help handed
Ittai
I'll assume by dialog you mean a popup that is invisible at page load and made visible by, say, a click on something in the existing HTML. A simple strategy to make this happen is wrapping the existing HTML.
I have no experience with option 1. As for 2, all you need to alter in the existing HTML is
adding the JS import, e.g.
<script type="text/javascript" language="javascript" src="/com.your.org.Module/com.your.org.module.client.Module.nocache.js"></script>
then adding an id to some clickable element you want to activate your dialog, e.g.
<button id="launchDialog">Show Dialog</button>
and finally adding an empty div with an id to insert your dialog into the DOM.
<div id="dialog"></div>
Then all you need in your Module is
public class Module implements EntryPoint {
#Override
public void onModuleLoad() {
Button b = Button.wrap(DOM.getElementById("launchDialog"));
b.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
RootPanel panel = RootPanel.get("dialog");
Widget w = ... // your dialog widget here
panel.add(w);
}
});
}
}
Lastly, you can play with the visibility of your popup div with the "display: none" style and the show() and hide() methods on the widget.