ASP.NET Using DB-Context in _layout.cshtml - asp.net

I'm trying to access the database context from _layout.cshtml to select notifications and display them in a dropdown box.
Can anyone tell me how to get the context in layout? I'm using razor-pages.

Look into ViewComponents. They are perfect candiates for this task. You can hookup to a db and return the data to your dropdown component then you can add them to your layout page like this.
#await Component.InvokeAsync("NotificationList", new { maxPriority = 2, isDone = true })
or like a tag helper
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-2.1

Related

How to add script to ASP.NET Core partial view properly?

I am new to ASP.NET.
I needed to show a list of items. I made a partial view to represent each item. It works fine.
I needed to add a script in the partial view. So I created a new javascript file in wwwroot > js. Then referenced it from the partial view, like this:
<script src="~/js/testjs.js"></script>
And this is the javascript file:
var upbtn = document.getElementById("upbtn");
var dnbtn = document.getElementById("dnbtn");
upbtn.onclick = upbtn_click;
dnbtn.onclick = dnbtn_click;
function upbtn_click() {
upbtn.children[0].children[0].style.fill = "green";
dnbtn.children[0].children[0].style.fill = "gray"
}
function dnbtn_click() {
upbtn.children[0].children[0].style.fill = "gray";
dnbtn.children[0].children[0].style.fill = "green";
}
The problem is with the script. It only executes fot the first partial view, not for the others.
So, for the first partial view, when I click the buttons, I can see the changes. But for the rest of the partial views, they have no effect. What should I do to make the script work for all partial views?
The project is using ASP.NET Core.
The reason you are seeing your functions only get called for the first partial view is due to how that javascript code works and the fact that the same element id's and javascript is being repeated in each partial view.
For example, the first partial view gets rendered and your onclick events get hooked up for your two elements with id's "upbtn" and "dnbtn". When the second partial view gets rendered (and any others after that), that document.getElementById runs, and finds the first element with that id in the document, which will be that of the first partial. (also element id's should be unique throughout a page, so you should look at ways to get unique id's in repeated partial views after you get this working. I didn't add that to this answer so as to keep focused on this question/answer)
In order to get this working, you need to re-design how the elements in your partials are calling the js functions, and you can move the js out to the parent view or to a single shared js file for your site. Note I'm making some assumptions/estimates on html elements below since you did not share that code.
For your upbtn/dnbtn elements, you can change them to something like below. The "buttonsParentElement" div is so we can get to the other btn elements children upon any click.
<div id="buttonsParentElement">
<div id="upbtn" onclick="upbtn_click(this)">UP</div>
<div id="dnbtn" onclick="dnbtn_click(this)">DOWN</div>
</div>
Then update your js methods (again, not in the partial but either in the parent view, or a shared js file):
function upbtn_click(element) {
element.children[0].children[0].style.fill = "green";
var relatedDnBtn = element.closest("#buttonsParentElement").querySelector("#dnbtn");
relatedDnBtn.children[0].children[0].style.fill = "gray"
}
function dnbtn_click(element) {
var relatedUpBtn = element.closest("#buttonsParentElement").querySelector("#upbtn");
relatedUpBtn.children[0].children[0].style.fill = "gray";
element.children[0].children[0].style.fill = "green";
}

Xamarin Forms Tabbed Page to have overlapping Custom View

I need to have something like that with XF Tabbed Page:
I.e., I need some panel which would appear over the whole content (including any tabs) where I can add some custom content. (The reason why I am asking it here, as it wouldn't be an issue in case of common simple page, when I would just have some overlapping view placed on the page).
In functionality it should be something like Action Sheets, but be cross-platform (i.e., defined as common XF view) and include custom content.
But it must be not necessary custom renderers with actually Action Sheet implementation (and AlertDialog accordingly to this). It would be perfect to have some view placed somewhere (I don't know where) in the page layout structure to achieve this.
Or Action Sheet and AlertDialog (with custom renderers) are still the easiest way to have it these days in XF? Thanks!
You can use ACR User Dialogs, and you can specify the UseBottomSheet option to make the action sheet appear at the bottom. Its available as a NuGet package, so there is no need for any custom renderers.
Acr.UserDialogs.ActionSheetConfig = new Acr.UserDialogs.ActionSheetConfig();
config.UseBottomSheet = true;
config.Title = "My Options";
config.Add(
"Option 1",
() =>
{
Device.BeginInvokeOnMainThread(async () => {
await DisplayAlert("", "Clicked option 1", "OK");
});
},
null);
config.Cancel = new Acr.UserDialogs.ActionSheetOption("Cancel");
And to display it:
Acr.UserDialogs.UserDialogs.Instance.ActionSheet(config);

Where to populate multiple dropdown lists

I'm trying to determine the correct approach to populating multiple dropdown lists on a view page of an .net MVC application, which is using angularJS.
In my app, designed as a silo-SLA app. I'm using the angular ngRoute module, and the $routeProvider to describe the multiple HTML pages for a single CSHTML page.
.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/club', { templateUrl: '/App/Club/Views/MCLView.html', controller: 'mclViewModel' });
$routeProvider.when('/club/list', { templateUrl: '/App/Club/Views/MCLView.html', controller: 'mclViewModel' });
$routeProvider.when('/club/show/:clubId', { templateUrl: '/App/Club/Views/ClubView.html', controller: 'clubViewModel' });
$routeProvider.otherwise({ redirectTo: '/club' });
$locationProvider.html5Mode(true);
});
My CSHTML page is basically empty except for the <div ng-view></div> tag. The routed HTML pages get loaded into the ng-view div.
<div data-ng-app="club" id="club" data-ng-controller="rootViewModel">
<h2>{{ pageHeading }}</h2>
<div ng-view></div>
</div
Each html view page loaded into the ng-view has an associated viewmodel javascript controller.
I started out populating the first dropdown on the html page by using $http.get in the angular controller to get the list data (json) from a server call. Then do a JSON.parse on the result.data and populate the select list control that is defined in the html page.
$scope.refreshColorsDropdown = function () {
var sel = document.getElementById('colorDropdown');
var colors = JSON.parse($scope.mycolors);
angular.forEach(colors, function(color) {
var opt = document.createElement('option');
opt.innerHTML = color.name;
opt.value = color.hex;
sel.appendChild(opt);
});
}
I could continue this approach for each dropdown on my page, creating several server calls to populate all my dropdowns ... but this seems tedious and code heavy.
Would a reasonable approach be to consider building one server calls that returns multiple collections, one for each dropdown, and then I'd parse those to populate all the dropdowns?
I'd like to pre-populate the lists on the server side C# code, however my cshtml files are empty except for the ng-view div, so there's no coding going on there.
So to my question ... if my HTML views contain all the html content, and the cshtml are empty ... what strategy should I be using to populate multiple html list controls from the server side?
Using MVC, you can make a ViewModel that contains all collections needed and return this collection to your Angular Controller.
Your View Model would be something like:
public class MyViewModel
{
public List<ColorModel> Colors{get;set;}
public List<FabircModel> Fabrics {get;set;}
}
In your MVC Controller:
MyViewModel mvm = new MyViewModel();
mvm.Colors = get colors here;
mvm.Fabrics = get fabrics here;
return Json(mvm, JsonRequestBehavior.AllowGet);
In your success object in Angular:
myservice.getData()
.success(function(data){
$scope.colors = data.Colors;
$scope.fabrics = data.Fabrics;
})
Hopefully, that helps or at least gets you started.
If you ignore the fact you are using angular the answer would be to populate a view model with what you need and razor the cshtml, because you are using angular...nothing changes....because you said SERVER-SIDE that is still the answer.
If you move this to the client an angular service that can cache the data is probably the most direct way.

How to update a value of _Layout from its PartialView in ASP.NET MVC 'Razor'?

I've been looking for the solution and I haven't find a way to get my head around it. So I hope you could give me some clues to achieve that.
Basically I need to change a value of a _Layout from its rendered PartialView. I use to do this using webforms .aspx master pages and FindControl method but I cannot find a solution to do this in MVC Razor engine.
My Layout page has an ActionLink and a div tag place-holder to display the partial-views, Now I need to know how to change the value of Text1 from the partial-view pages within the DIV tag:
Is JavaScript the only way that I can do this ?
<input id="Text1" type="text" />
<div>
#Ajax.ActionLink("Personal Info", "Personal", "Portal", new { area = "Resume" },
new AjaxOptions { UpdateTargetId = "result", HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnBegin = "blockUi",
OnSuccess = "onTabChanged(this, 'Personal Information')"
},
new { #class = "text-strong" })
</div>
<div id="result">#RenderBody()</div>
Appreciate your contributions in advance.
Javascript is the way this is handled I think.
You might be able to do some trickery with controllers and the ViewBag (like how the page title is set with the ViewBag in a default MVC project).
You could also maybe set it to some global variable or something, and have your partial view change that variable.
Both those solutions though would require a page reload.
But using javascript is probably the best, you could do it in the onTabChanged function.
<script>
function onTabChanged(param1, param2) {
var el = document.getElementById("Text1");
el.value = "Whatever you want here";
}
</script>
I think the easiest way is using a ViewBag that you play around with in your controller/view/partial view.
In WebForms you can use the FindControl method because a PostBack was made. So the entire page was rendered again.
In the example you posted, I assumed that the request made by Ajax.ActionLink that update the div result, returns a view that may use the same Layout, but is in another context so you don't have access to the same input text from the rendered page where Ajax.Action link was triggered.
So, if you have multiples Ajax.ActionLink that updates the <div id="result">, you need to handle the success method on onTabChanged, like #Kyle Gobel suggested.

How to access properties of a Tridion component like schema name based on which it is created in aspx page?

I am customizing the ribbon tool bar by adding a button to it in TRIDION 2011 SP1 version.
When I click on the button it will open an aspx page.Inside that aspx page I need to access the name of the schema used to create that component before creating the component itself(I mean to say while creating the component itself).
Please provide me a way to solve this issue. Thanks in advance.
You should pass it to your popup. The URI of the Schema is available on the Component model object within the CME - so your button command can access it and pass it to the popup (in the URL, for example).
var schemaId = $display.getView().getItem().getSchemaId();
If you have the component (as an object), you can get it's schema id as Peter indicated. If you only have the component id, you can load the component and through that get to the schema.
When you need to load any item, you have to be aware that it's not a synchronous call in the UI API, so you should use delegate methods for that. For example something like this:
Example.prototype._loadItemInformation = function Example$_loadItemInformation(itemId, reload) {
var item = $models.getItem(itemId);
if (item) {
var self = this;
function Example$_loadItemInformation$_onItemLoaded() {
$evt.removeEventHandler(item, "load", Example$_loadItemInformation$_onItemLoaded);
// proceed with the actions on the loaded item here
};
if (item.isLoaded(true) && !reload) {
Example$_loadItemInformation$_onItemLoaded();
}
else {
$evt.addEventHandler(item, "load", Example$_loadItemInformation$_onItemLoaded);
//$evt.addEventHandler(item, "loadfailed", Example$_loadItemInformation$_onItemLoadFailed);
item.load(reload, $const.OpenMode.VIEW);
}
}
};
Also be aware the item could fail loading, you should actually also register an event handler for loadfailed (as my example code neglects to do).

Resources