Sharing controller JavaFX [duplicate] - java-8

I have created a root FXML which is a BorderPane and it has his own root controller.
I want to dynamicly add FXML's to the center of this borderpane.
Each of these fxml's share the same controller, root controller. I have done this in netbeans by choosing an exsisting controller when creating an empty FXML file.
I also have gave the nodes different id names, but the root controller does not recognize the nodes in these fxml's.
Is it possible to share the same controller for different fxml's?
Thanks in advance

Background
I don't know that sharing a controller instance is really recommended, at least I've never seen it done before.
Even if you set the controller class in each of the fxml's you are loading to the same value, it isn't going to share the same controller instance, because every time you load a controller, it will create a new instance (object) of the controller class (which doesn't seem to be what you want).
Potential Solutions
I haven't tried either of these solutions, but believe they will work.
The initialize method will probably be called each time you load a new fxml file. So you will want to account for that in your logic by making initialize idempotent.
A. Manually set the controller instance.
Remove all of the references to your controller class from your fxml files.
Manually create an instance of your controller class.
MyController controller = new MyController();
Set the controller to your controller instance before you load each fxml.
FXMLLoader loader = new FXMLLoader();
loader.setController(controller);
Panel panel = (Panel) loader.load("myfxml.fxml");
Repeat step 3 for each of your fxml files, using the same controller reference each time.
B. Use a controller factory.
You can set a controller factory on your fxml loaders and have the controller factory always return the same controller instance.

Related

Using Spring Boot, Thymeleaf and Oracle: How to dynamically populate the submenus in a web site menu defined in a fragment?

I have a web site that consists of approximately 30 html thymeleaf templates. I have a home_navigation.html fragment that gets included in all templates as the header. This header defines a main navigational menu with popup submenus. The popup submenus under one of my main menus needs to be generated from my oracle database table.
Normally when passing data from a database into a Thymeleaf template I would put the code in the controller to call the java DAO and return a list of Link objects and then add that list in the controller to the model using .setAttribute. Then in the Thymeleaf template I would iterate through the "${List}" in a "th:each" outputting the "<a href..." for each Link object in the list. That is all fine and dandy.
I also can pass parameters into the fragment. So that isn't the problem BUT...
Since the main navigational menu is added as a header fragment into the beginning of every template then I would have to go into every defined controller and add code that would pull the list of Links and pass it into the template and then pass the list into the fragment from every page. that would be approximately 30 times!!!
How...using Spring Boot and Thymeleaf, does someone feed data into a fragment to populate a menu dynamically from a database that is then added as a header fragment into every page/template on the site?
Is there a way to create a controller for the fragment and somehow have every page call the controller for the fragment before the fragment contents are put into every page?
Thank you.
There are a number of ways to solve this problem depending on whether your menu can change while the user is logged in. If it can change then you can create a base controller class that has a method annotated with #ModelAttribute. All of your controllers would inherit from this base class. This method would obtain the menu items and add them to the model each time a page is requested. A simplistic example of such a class is:
#Component
public abstract class BaseController {
#Autowired
private AlphabetService alphabetService;
#ModelAttribute(name = "alphabet")
public List<String> getAlphabet() {
return alphabetService.getCharacters();
}
}
Your page would access them as normal
th:each="character : ${alphabet}"
You could also access the service directly in the page by doing something like
th:each="character: ${#alphabetService.getCharacters()}"
If the menu items do not change while the user is logged in then you could add #SessionAttributes("alphabet") at the class level to the above example and the service method would be called only once when the first page is displayed and cached in the session for future access.

How to set global viewmodels in ASP .NET Core 3.1?

I am new to ASP.NET Core and have some trouble with binding global models and viewmodels to razor views. My application is a mixture of Web API and MVC with razor views.
My goal
When I open an ASP.NET MVC page, I need to instantiate a model by loading it from the database (DbContext service) based on an id received in a cookie. I want to use this model object globally in every view or partial view.
Current Implementation
I can access the cookies in action methods of page controllers, so that I have to load the model from the DbContext in every action method and bind it as viewmodel to target view. This is not practical, because I have to do this in every page controller, because I need that model object on all pages in my navigation pane.
Idea
I think it should be possible to access to Cookies and dbcontext within Startup.cs and bind the model object to _ViewStart.cshtml, so that it is accessible globally in every view or partial view. Even this approach were correct, I do not have any idea how the code would look like. Because I am learning Web-Apps with .NET Core by learning by doing and try and error at the moment. :(
UPDATE
I have a layout page _Layout.cshtml, which includes partial views like the _NavPane.cshtml. My goal is to pass a Model object to the _Layout, which is instantiated via loading from the database (I have a service IMandantRepository for this purpose) and dependent on a cookie.
That model object is needed on every page request. That's why it would be a better practice to load the model object outside the MVC page controllers and pass it to them (what I can not implement technically).
I tried to find a solution by myself and ended up in following interim ugly solution. Following is the content of the _ViewStart file. On the bottom I assign the needed global variables, which I can use in every view or partial view.
This solution has at least two disadvantages:
The model object is possibly loaded redundantly.
Too many program logic in a view file.
#inject MyProject.Data.IMandantRepository mandantRepo
#{
// Main layout template
Layout = "_Layout";
// Define default values
bool showAdminSection = false;
string src = "/images/logos/nologo.png";
// Read cookie value
string currentMandantUid;
Context.Request.Cookies.TryGetValue("currentMandant", out currentMandantUid);
// Load mandant from the database
var thisMandant = mandantRepo.GetMandantByUid(currentMandantUid);
if(thisMandant is Mandant){
src = "data:image/*;base64," + thisMandant.GetBase64Logo();
showAdminSection = thisMandant.Abbr == "AdminMandant";
}
// Assing global variables to ViewData
ViewData["CurrentMandant"] = thisMandant;
ViewData["logoSrc"] = src;
ViewData["showAdminSection"] = showAdminSection;
}
This is an example code in ConfigureService() of Startup.cs. You can register your dbContext class in this way.
services.AddDbContext<BookStoreContext>( options =>
options.UseSqlServer(_configuration.GetConnectionString("DefaultConnection")));

Call another.js view from alloy.js titanium

have 1st view = index.js
2nd view = another.js
global file alloy.js
I have called the global class (alloy.js) method from index.js and now i want to move to another.js view but after httpRequest method finishes (which is declared and implemented in alloy.js).
---alloy.js---
Alloy.Global.httpMethod=function(){
//xml response is achieved, now from here i want to navigate to another.js view
}
---index.js---
Alloy.Global.httpMethod();
---another.js---
//some UI objects.
The first thing you want to do is create a controller, your another.js must be a Controller, it can be created by doing Right click on app and creating a new controller from there.
Once your controller is created, you can easily do what Phil said in the comment. i.e
Alloy.createController('another').getView().open();
This has to be placed in your onload function of HttpClient.
Hope it Helps.

Custom MVC Framework: How do I propogate data to a view?

I am creating a custom MVC framework.
I verrrrry loosely modeled it after the codeIgniter framework, but it's ground-up custom for the most part.
I'm at the point where I have URL's routing to the appropriate controller actions, but I'm stuck at the point where I generate a view that can utilize data generated by the controller.
I have views defined (static HTML with inline php ready to populate dynamic data), and I have the destructor of my base controller require()'ing the view in order to populate the browser with the view... here's the code:
public function __destruct()
{
if ($this->bSuppressView === false)
{
require(APP_PATH.'views/layout/header.php');
require(APP_PATH.'views/'.$this->sController.'/view.'.$this->sController.'.'.$this->sAction.'.php');
require(APP_PATH.'views/layout/footer.php');
}
}
Basically, when the controller is done executing, the teardown process of the base controller will then include the global header view, the controller's action's view, and then the global footer view, which should populate the webpage with everything for the URL that was requested...
HOWEVER, I cannot access any globally defined variables from the embedded php in the view code. In my bootstrap class, I define a bunch of local variables such as my config variable, etc., but the view seems to consider those variables undefined. Additionally, i'm unsure how to allow the view to access data that the controller may have generated. Where do I "stick" it to make it available to the view?
Let me know if this isn't clear, and i'll update.
Thanks!
UPDATE: I've discovered that while doing it this way, the "environment" of the views is within the controller object, which, as far as I can tell is a great thing! I don't have to propogate anything anywhere but in the controller, and I can use "$this->" in the views to get access to anything public or private from within the controller class!!!
That leaves the question: is this "normally" how it's done in MVC? What's the BEST way to propogate a view? I think this will suit my purposes, and I will post back if I discover a limitation to just treating the embedded view php as "within the scope of the calling controller"...
The way this is generally done, is that the view is actually an object. You pass that object you're variables, and that view object takes the template you gave it, includes it so that it's in the current scope, and grab the output into a variable using output buffering.
To give you a basic idea:
// controller object
$this->set('key','val');
$this->render('mytemplate');
// controller base class
$view = new View;
$view->setData($this->getData());
// view class
class View {
....
function render() {
ob_start();
include $this->resolveTemplate();
$out = ob_get_contents();
ob_end_clean();
return $out;
}

Prism / MEF new view not getting a new viewmodel from MEF import

I have a tabbed application where I want the user to be able to search for a person and then, in a new view, show the person's details. The user should be able to have multiple person detail views open for different people.
I was a little unsure if I am following the correct procedure for creating my new view. Using Unity (which I am not) it seems you would call Container.Resolve(view) however I am doing the following, the satisfyImports was necessary in order for my imports in the view / viewmodel to be created.
PersonDetailView view = new PersonDetailView();
_container.SatisfyImportsOnce(view);
_regionManager.Regions["MainRegion"].Add(view, this.SelectedPerson.Name);
_regionManager.RequestNavigate("MainRegion", new Uri("PersonDetailView", UriKind.Relative));
In the code for my PersonDetailView I have the following property to set the data context.
[Import]
public PersonDetailsViewModel ViewModel
{
set
{
this.DataContext = value;
}
}
This seems to work but the trouble I am having is that when I create a second person view, the new view is getting the same instance of the datacontext as the view that is already created.
Is this because I am creating my views incorrectly or is there a way that I tell MEF to create a new oject when it fulfills the imports for my new view?
When you export a part, by default it used a CreationPolicy of Shared. This essentially makes the exported instance a singleton in the container. With your export, add another attribute:
[Export, PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo { }
This will ensure a new instance is created each time you call to compose the consumer instance.

Resources