Ext.net howto access treepanel nodes - c#

I am a beginer in ext.net. I have created a simple tree with dynamic loading using proxy from out database.
#{
Layout = null;
}
#{
var thisPlugin = Model as IPlugin;
if (thisPlugin == null)
{
throw new Exception("IPlugin expected");
}
var loadChildrenFunc = new Func<string>(() =>
{
string retVal = Url.Action("GetChildren/" + Url.Encode(thisPlugin.Id));
return retVal;
});
var tree = Html.X().TreePanel().ID("FACILITY_TREE");
}
#(tree.Title("Facility tree")
.Icon(Icon.Table)
.Frame(true)
.Height(450)
.Width(300)
.Border(false)
.Store(Html.X().TreeStore().Proxy(Html.X().AjaxProxy().Url(loadChildrenFunc())))
.Root(Html.X().Node().NodeID("0").Text("Facility objects tree")))
Treepanel succesfuly created and loads nodes.
The problem I have is to acces tree to save it state.
For example then expand/collapse nodes i need to call controller and save treeview state. So the question is how to solve it?
Anoter, after click/double click i need to call JS function to modify some data on page.
Please help. Thanks!

i think you need to add a event listener.
like this
listeners: {
collapse: function() {
alert('collapsed');
},
expand: function() {
alert('expand')
},
itemclick: function(s,r) {
alert(r.data.text);
}
}
hope this helps

Related

Change and save bool state to true on record in MVC Controller in the action

I would like to change the state of a bool to true while the current action is taking place. The action result gets the id from the razor page and then creates a link in my sitemap. While it is doing that i would like it to change the state of the bool in the record and save it. I have tried implementing this code in the controller but with no success.
var isadded = db.Sitemaps.Where(m => m.IsAdded == false).FirstOrDefault();
isadded.IsAdded = true;
This does not work because it has no idea what record it is supposed to change and does not have a save.
I have this in my code already.
public ActionResult AddNewSitemapElement(int? id)
and then i make sure it isn't null and return a badRequest if it is. Then i have the code below to use throughout the Action.
MySitemap mySitemap = db.Sitemaps.Find(id);
Is there a way to incorporate using the id in a string to change this? Also should i put it at the bottom of the Action so it does it after adding the data to the XML or does it not matter?
Thanks for your help!
Update:
I added this block of code to the action and it seems to work. From the advice of comment below. I already know the state of the bool before this happens. This bool only controls the show of a button to add the link to the XML in the view. So once it is created in the database the button is there to add it to the xml. So i know it is false already. However this seems to work. Would be glad to know if this is the best approach or not.
if (mySitemap.IsAdded == false) {
mySitemap.IsAdded = true;
db.SaveChanges();
}
Update:
Below is my full Controller Action. It does work as is. If there is a more proper way to implement this then feel free to comment.
public ActionResult AddNewSitemapElement(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
MySitemap mySitemap = db.Sitemaps.Find(id);
if (mySitemap.IsAdded == false) {
mySitemap.IsAdded = true;
db.SaveChanges();
}
SitemapGenerator sg = new SitemapGenerator();
//create a sitemap item
//var siteMapItem = new SitemapItem(Url.Action("NewAdded", "NewController"), changeFrequency: SitemapChangeFrequency.Always, priority: 1.0);
var siteMapItem = new SitemapItem(PathUtils.CombinePaths(Request.Url.GetLeftPart(UriPartial.Authority), "/" + mySitemap.Category + "/" + mySitemap.Location),
changeFrequency: SitemapChangeFrequency.Daily, priority: (mySitemap.Priority), lastModified: (mySitemap.LastModified));
//Get the XElement from SitemapGenerator.CreateItemElement
var NewItem = sg.CreateItemElement(siteMapItem);
//create XMLdocument element to add the new node in the file
XmlDocument document = new XmlDocument();
//load the already created XML file
document.Load(Server.MapPath("~/Sitemap.xml"));
//convert XElement into XmlElement
XmlElement childElement = document.ReadNode(NewItem.CreateReader()) as XmlElement;
XmlNode parentNode = document.SelectSingleNode("urlset");
//This line of code get's urlset with it's last child and append the new Child just before the last child
document.GetElementsByTagName("urlset")[0].InsertBefore(childElement, document.GetElementsByTagName("urlset")[0].LastChild);
//save the updated file
document.Save(Server.MapPath("~/Sitemap.xml"));
return RedirectToAction("Index", "Sitemap");
}
This is a general pattern to ensure you are only updating the individual entity and return it where applicable.
public ActionResult AddNewSitemapElement(int? id)
{
if (id != null)
{
var mysitemap = db.Sitemaps.where(x => x.id == id.Value && !x.IsAdded).FirstOrDefault();
if(mysitemap != null)
{
mysitemap.IsAdded = true;
DB.SaveChanges();
}
return mysitemap;
}
return null;
}

Passing object containing object from model to view in ASP.NET

Usin ASP.NET I am trying to add a list of profiles to a object in a model and then enumerate over this list in the view.
public ActionResult Index(BlogPage currentPage)
{
var model = new BlogPageModel(currentPage);
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
foreach (LinkItem linkItem in currentPage.ProfileArea)
{
var page = _pageDataHelper.GetPageData(linkItem);
var profilePage = page as ProfilePage;
if (profilePage != null)
{
profilePages.Add(profilePage);
}
}
model.Profiles = profilePages;
}
return View(model);
}
Using this code in the view:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
However above code returns the error:
CS0030: Cannot convert type 'Models.Pages.BlogPage' to 'Models.Pages.ProfilePage'
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
Thanks!
Hi Its seems that you have problem in the for each loop,but i couldn't exactly figure out the problem line, since model is not available above.
Answer to your question:
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
ex:
public class somemodelname
{
public list<anytype> somepropertyname{get;set;}
}
accessing:
#foreach (var singlevalueOrObj in Model.somepropertyname)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<singlevalueOrObj >(profile))
}
In the above way you can store any list object inside your model and for rendering the page as same way as you did in the above that is using the partial view.
Hope above information was helpful.
Thanks
Karthik
You have a typo in your foreach loop:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
You are looping over the property BlogPages not the property Profiles that you set with a ProfilePage collection in your controller:
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
...shortened for length...
model.Profiles = profilePages; // Right here is what you intended to loop over
}

How can I use knockout.js to bind data in my C# code behind to a select element on the front-end?

Here is the part of the UI that I'm trying to update:
<label>Country</label>
<select name="country" data-bind="options: $parent.CountryList, optionsCaption: '- Select -'"></select>
As you can see, I tried $parent.CountryList because I was hoping that would refer to the CountryList in the code behind. Here is a snippet of the Page_Load function where I'm storing data from a database into a list of countries:
using (CCGEntities db = new CCGEntities())
{
List<Country> CountryList = db.Countries.ToList();
}
The goal is to take the list of countries and have them populate the select element as a dropdown menu. I tried mimicking the binding for asp:DropDownList but the code behind didn't pick up on an ID attribute for the select element. Would I be better of doing this with asp:DropDownList?
That is not how you must do it in ASP.NET. You must create ViewModels and bind them using ko.applybindings(viewModel, YOUR_HTML_ELEMENT_ROOT). In order to do that, the model should either:
a) Be serialized at run time by the server and dumped into a javascript variable
or b) Fetched dynamically with javascript and then apply the binding
A complete example of how to achieve this with Entity Framework, ASP.NET and Knockout is available here.
Dropdownlist population with knockout.js can seem a bit tricky at first. I ve implemented a knockout binder to make this easier:
ko.extenders.autoOptions = function (target, type) {
target["Options"] = [];
console.log("getting options for type: " + type);
target.Options = ApplicationGateway.getOptions([ApplicationName.Api.Options]+type);
return target;
};
This binder can be used in the following manner in your javascript models:
self.Gender = ko.observable().extend({ autoOptions: 'GENDER', required: { message: 'Gender is required' } });
Which results in the following template usage:
<select data-bind="options: Gender.Options,
value: Gender,optionsText: 'Text',optionsValue: 'Value'">
</select>
My Asp.Net Web API Options Controller looks like this:
public class OptionsController : ApiController
{
private ResourceManager _resourceManager;
private CultureInfo _cultureInfo;
[HttpGet]
[Route("api/Options/{type}")]
public List<ListItem> List(string type)
{
_resourceManager = new ResourceManager("Application.Resources.RESOURCE", typeof(APPLICATION).Assembly);
_cultureInfo = new CultureInfo(Application.CurrentSession.User.LanguageSelected);
switch (type.ToUpper())
{
case "GENDER": return Gender();
...
}
return new List<ListItem>();
}
private List<ListItem> Gender()
{
var items = new List<ListItem>
{
new ListItem(_resourceManager.GetString("Label_Gender_Male", _cultureInfo),Domain.Enums.Gender.Male.ToString()),
new ListItem(_resourceManager.GetString("Label_Gender_Female", _cultureInfo), Domain.Enums.Gender.Female.ToString()),
};
return items;
}
}

How to move CSS inline with PreMailer.Net whilst using MvcMailer for sending HTML emails

Using MvcMailer, the problem is that our emails are being sent without our CSS as inline style attributes.
PreMailer.Net is a C# Library that can read in an HTML source string, and return a resultant HTML string with CSS in-lined.
How do we use them together? Using the scaffolding example in the MvcMailer step-by-step guide, we start out with this example method in our UserMailer Mailer class:
public virtual MvcMailMessage Welcome()
{
return Populate(x => {
x.ViewName = "Welcome";
x.To.Add("some-email#example.com");
x.Subject = "Welcome";
});
}
Simply install PreMailer.Net via NugGet
Update the Mailer class:
public virtual MvcMailMessage Welcome()
{
var message = Populate(x => {
x.ViewName = "Welcome";
x.To.Add("some-email#example.com");
x.Subject = "Welcome";
});
message.Body = PreMailer.Net.PreMailer.MoveCssInline(message.Body).Html;
return message;
}
Done!
If you have a text body with HTML as an alternate view (which I recommend) you'll need to do the following:
var message = Populate(m =>
{
m.Subject = subject;
m.ViewName = viewName;
m.To.Add(model.CustomerEmail);
m.From = new System.Net.Mail.MailAddress(model.FromEmail);
});
// get the BODY so we can process it
var body = EmailBody(message.ViewName);
var processedBody = PreMailer.Net.PreMailer.MoveCssInline(body, true).Html;
// start again with alternate view
message.AlternateViews.Clear();
// add BODY as alternate view
var htmlView = AlternateView.CreateAlternateViewFromString(processedBody, new ContentType("text/html"));
message.AlternateViews.Add(htmlView);
// add linked resources to the HTML view
PopulateLinkedResources(htmlView, message.LinkedResources);
Note: Even if you think you don't care about text it can help with spam filters.
I recommend reading the source for MailerBase to get a better idea what's going on cos all these Populate methods get confusing.
Note: This may not run as-is but you get the idea. I have code (not shown) that parses for any img tags and adds as auto attachments.
Important part is to clear the HTML alternate view. You must have a .text.cshtml file for the text view.
If you're using ActionMailer.Net(.Next), you can do this:
protected override void OnMailSending(MailSendingContext context)
{
if (context.Mail.IsBodyHtml)
{
var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(context.Mail.Body);
context.Mail.Body = inlineResult.Html;
}
for (var i = 0; i < context.Mail.AlternateViews.Count; i++)
{
var alternateView = context.Mail.AlternateViews[i];
if (alternateView.ContentType.MediaType != AngleSharp.Network.MimeTypeNames.Html) continue;
using (alternateView) // make sure it is disposed
{
string content;
using (var reader = new StreamReader(alternateView.ContentStream))
{
content = reader.ReadToEnd();
}
var inlineResult = PreMailer.Net.PreMailer.MoveCssInline(content);
context.Mail.AlternateViews[i] = AlternateView.CreateAlternateViewFromString(inlineResult.Html, alternateView.ContentType);
}
}
base.OnMailSending(context);
}
If you don't like using AngleSharp.Network.MimeTypeNames, you can just use "text/html". AngleSharp comes as a dependency of ActionMailer.Net.

Populate dijit menubar with data from sql database

I haven't worked so much with jquery, ajax and json before, but I want to learn how to use it using dojo and dijit. There are many tutorials, but few c# with sql database examples.
I've created a json output with dijit menubar data from my database which looks like this:
[{"MenuItemId":1,"MenuName":"Root","Tooltip":"Root","IsParent":true,"ParentId":0,"IsVisible":false,"SortIndex":null},
{"MenuItemId":3,"MenuName":"Blogg","Tooltip":"Min Blogg","IsParent":false,"ParentId":1,"IsVisible":true,"SortIndex":1000},
{"MenuItemId":4,"MenuName":"Administrasjon","Tooltip":"Viser Administrasjon","IsParent":true,"ParentId":1,"IsVisible":true,"SortIndex":10000},
{"MenuItemId":5,"MenuName":"DropMenu","Tooltip":"Drop menu","IsParent":true,"ParentId":1,"IsVisible":true,"SortIndex":9000},
{"MenuItemId":6,"MenuName":"Menuitem1","Tooltip":"Menuitem1","IsParent":false,"ParentId":5,"IsVisible":true,"SortIndex":9001},
{"MenuItemId":9,"MenuName":"Menuitem2","Tooltip":"Menuitem2","IsParent":false,"ParentId":5,"IsVisible":true,"SortIndex":9002}]
I want to bind these data to dijit menubar, but I haven't figured out how to doo it yet.
Here is the code I've made so far. I've been trying back and forth, but I haven't managed to get data out from the json data I try to get.
Here is a sample in where I try to get data out of my json data output. The sample is trying to write data in console view, but I want to populate a dijit manybar:
<script>
require([
"dijit/MenuBar",
"dijit/PopupMenuBarItem",
"dijit/Menu",
"dijit/MenuItem",
"dijit/DropDownMenu",
"dojo/dom",
"dojo/request",
"dojo/json",
"dojo/_base/array",
"dojo/domReady!"
], function(MenuBar, PopupMenuBarItem, Menu, MenuItem, DropDownMenu, dom, request, JSON, arrayUtil) {
console.log('hello world');
// Results will be displayed in resultDiv
var resultDiv = dom.byId("resultDiv");
// Request the JSON data from the server
request.get("/api/Menu", {
// Parse data from JSON to a JavaScript object
handleAs: "json"
}).then(function(data) {
// Display the data sent from the server
var html = "";
var pMenuBar = new MenuBar({});
var pSubMenu = new DropDownMenu({});
console.log('data : ' + data.toString());
arrayUtil.forEach(data.items, function(item, i) {
console.log(item[0].value);
//console.log('item :' + item.name + '\r\n');
//console.log('value : ' + item.value + '\r\n');
});
//html += "<dt>" + item.name +
// "</dt><dd>" + item.value +
// " (" + (typeof item.value) + ")</dd>";
//});
//resultDiv.innerHTML = html;
//pMenuBar.placeAt("wrapper");
//pMenuBar.startup();
},
function(error) {
// Display the error returned
resultDiv.innerHTML = error;
});
});
</script>
What I need is a an example in how to iterate json data to populate dijit menubar.
<body class="claro">
<div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'sidebar', gutters:true, liveSplitters:true" id="borderContainer">
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="splitter:true, region:'leading'" style="width: 300px;">
<div id="markup" style="width: 300px; height: 300px"></div>
</div>
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="splitter:true, region:'center'">
<div id="wrapper"></div>
<div id="resultDiv"></div>
</div>
</div>
</body>
I could really use some help on this one. Thanks for all the advice I can get.
Thank you! :)
Kind regards,
Jon Haakon
I think I would make a recursive function that burrows down into the JSON structure you receive from the server, and builds menu items along the way.
Annoyingly, there is a small difference between items in the menu bar itself, and items in submenus belonging to the menu bar. The menu bar wants dijit/PopupMenuBarItem and dijit/MenuBarItem objects, while the popup menus themselves want dijit/PopupMenuItem and dijit/MenuItem, correspondingly.
Here's an example:
function recursiveMakeMenuItem(data, id, inMenuBar) {
// Get the item itself and its children (if any)
var item = arrayUtil.filter(data, function(i){return i.MenuItemId==id;})[0],
subs = arrayUtil.filter(data, function(i){return i.ParentId==id;}),
widget = null, menu = null;
if(subs.length) {
// This item has children, so we need to make both an item that
// triggers the a submenu (differentiating between items in the
// menu bar and items in menus) and the submenu itself.
widget = inMenuBar ? new PopupMenuBarItem() : new PopupMenuItem();
menu = new Menu();
widget.set("popup", menu);
// We then recursively dig deeper to generate the sub menus.
arrayUtil.forEach(subs, function(item) {
menu.addChild(recursiveMakeMenuItem(data, item.MenuItemId));
});
}
else {
// No children, but again we need to differentiate between items
// in the menu bar and items in menus.
widget = inMenuBar ? new MenuBarItem() : new MenuItem();
}
widget.set("label", item ? item.MenuName : "ERROR id "+id);
return widget;
}
In your code, you would call this when you receive data from the server. For example, if you wanted the single item with ParentId 0 to be the top level menu bar item, you could do:
request.post("/echo/json/", {
handleAs: "json"
}).then(function(data) {
var pMenuBar = new MenuBar({region: "top"});
pMenuBar.addChild( recursiveMakeMenuItem(data.items, 1, true) );
dijitRegistry.byId("borderContainer").addChild(pMenuBar);
pMenuBar.startup();
});
Or, if everything with ParentId 1 should be top level items:
request.post("/echo/json/", {
handleAs: "json"
}).then(function(data) {
var pMenuBar = new MenuBar({region: "top"});
arrayUtil.forEach(data.items, function(i) {
if(i.ParentId !== 1) return;
pMenuBar.addChild(recursiveMakeMenuItem(data.items, i.MenuItemId, true));
});
dijitRegistry.byId("borderContainer").addChild(pMenuBar);
pMenuBar.startup();
});
Here's an example fiddle: http://fiddle.jshell.net/2Gpkd/1/

Categories