I have two pairs of controller and view. The first view contains a list of items, while the in second shows some details of a specific item. What I want to achieve is that a click on one list item, the function onSelect should call second controller of detail view and update its content with the selected list item.
So far I have following code:
//first list controller
onSelect : function () {
var secondController = sap.ui.controller("controller.Detail");
secondController.updateFunction("some text");
}
Then in second controller:
//second detail-controller
updateFunction: function (someText) {
var view = sap.ui.xmlview("view.Detail");
view.byId("someTextField").setText(someText);
}
The problem is that this is not working. It seems that sap.ui.xmlview is not returning the same view which is displayed.
When I execute following code:
var model = view.getModel(model);
console.log(model);
within 2 functions of detail controller, but first is called by outside controller and second is called by onInit or function called by detail view event, the id is different.
How can I achieve such a cross-controller function calling with updating content of different view? Or is my approach not proper?
I would recommend to use either the EventBus or Routing for inter view communication.
Routing is nice as it uses the hash part (#) of the url to communicate for example an event like the selection of an item (f.e. https://example.com/myUi5App/index.html#/item/123). The user can use the browser history and bookmarks to navigate through your app.
A view can register to the router to be notified when a specific url pattern is matched. The walkthrough in the SAPUI5 Developer Guide does nicely explain routing step by step and in detail here and here.
EventBus is a global object that can publish arbitrary events. Anyone interested can register to the EventBus. There is an EventBus on the Component which you should use if you have a component and a global EventBus.
Both techniques help decoupling your views. It does not matter if there are one, many or none views listening to the selection change. And it does not matter for the listeners who fired the event.
If both views have been called once you can achieve this via the view (from my opionion, this is quite hacky and should be solved otherway)
this.getView().byId("yourViewId").oController.yourMethod();
means in your case
onSelect : function () {
var secondController = this.getView().byId("view_id").oController;
secondController.updateFunction("some text");
}
maybe this helps you, he is passing the controller reference which would be a better option: Calling Controller Function from inside a press handler in sapui5
I have found solution.
sap.ui.getCore().byId("__xmlview1");
According to documentation var view = sap.ui.xmlview("view.Detail"); always creates a new view.
However I am still struggling about specifying id of xmlview. Since "___xmlview1" is dynamicly given name and the number 1 means serial number of views within application. So if I create another view before creation of "view.Detail", the id will point to the new one.
I am creating xmlview like this:
<mvc:XMLView viewName="view.Detail"></mvc:XMLView>
Related
I have a Vaadin grid that I use. I make a put request to update the scores of the elements in the grid. I was wondering how to make the grid respond after the update to show the new information. Right now I have to refresh the entire page to show the new information.
I'm not sure what code I would post, I'm using a basic vaadin grid if that helps.
I am not completely sure with what you mean by putting changes to the grid, but I suppose you are using setItems or a data provider?
For the first, you would have:
Grid<MyItem> grid = new Grid(MyItem.class);
grid.setItems(someItems);
While for the second you would write:
Grid<MyItem> grid = new Grid(MyItem.class);
grid.setDataProvider(...);
For the second way you can either specify the data provider using Java 8 notation as in:
grid.setDataProvider(
(sortOrders, offset, limit) -> {//e.g. call to repo },
() -> { // count provider, e.g. repo.count() });
or as in:
grid.setDataProvider(new ListDataProvider<>(myDataCollection));
To come to the question, in both cases you can call following to get the provider:
DataProvider<MyItem> provider = grid.getDataProvider();
To update one specific element, the data provider provides the method
provider.refreshItem(item);
Important to know is that the MyItem class has to implement a getId() method, or, alternatively, equals(). If this is not the case, you can invoke provider.refreshAll()
I have built a MVCPortlet that runs on Liferay 6.2.
It uses a PortletPReferences page that works fine to set/get String preferences parameters via the top right configuration menu.
Now I would need to store there a String[] instead of a regular String.
It seems to be possible as you can store and get some String[] via
portletPreferences.getValues("paramName", StringArrayData);
I want the data to be stored from a form multiline select.
I suppose that I need to call my derived controller (derived from DefaultConfigurationAction) and invoke there portletPreferences.setValues(String, String[]);
If so, in the middle, I will neeed the config jsp to pass the String[] array to the controller via a
request.setAttribute(String, String[]);
Do you think the app can work this way in theory?
If so, here are the problems I encountered when trying to make it work:
For any reason, in my config jsp,
request.setAttribute("paramName", myStringArray);
does not work ->
actionRequest.getAttribute("paramName")
retrieves null in my controller
This is quite a surprise as this usually works.
Maybe the config.jsp works a bit differently than standard jsps?
Then, how can I turn my multiline html select into a String[] attribute?
I had in mind to call a JS function when the form is submitted.
this JS function would generate the StringArray from the select ID (easy)
and then would call the actionURL (more complicated).
Is it possible?
thx in advance.
In your render phase (e.g. in config.jsp) you can't change the state of your portlet - e.g. I wouldn't expect any attributes to persist that are set there. They might survive to the end of the render phase, but not persist to the next action call. From a rendered UI to action they need to be part of a form, not request attributes.
You can store portletpreferences as String[], no problem, see the API for getting and setting them
I think maybe you can use an array in client side, and you can update the javascript array, when user is selecting new values.
So you have the javascript array, then when user click on the action, you can execute the action from javascript also, something like this:
Here "products" is the array with your products.
A.io.request(url, {type: 'POST',
data: {
key: products
},
on: {
success: function(event, id, obj) {
}
}
});
From Action methd you can try to get the parameter with:
ParamUtil.getParameterValues(request,"key");
I am using knockout mapping plugin to map JSON data to knockout view model. The issue is JSON comes from server data doesn't have all the properties always. But my computed obeservables refer them. So I creates all the observable in first mapping using an empty object(templateStructure) contains all properties and then doing seocond call with actual data to populate the observable with current data. This works fine but want to know that if there any better way to handle the situation?
This is how the two time call is happening right now. templateStructure is dummay object with all the properties and data is actual data.
ko.mapping.fromJS(templateStructure, {}, this);
ko.mapping.fromJS(data, {}, this);
Calling mapping.fromJS to update an existing view model is right. If you're receiving updates to your model using AJAX, it's the easiest way to do it (if you didn'd use mapping, you'd have to do it by hand, property by property).
Your approach of creating a "template viewmodel" with all the properties, so that they exist even if you don't receive it in you JSON responses is good. Besides, it's easier to understand the JavaScript code: you don't need to see the server side to discover which properties are in the view model, as would happen if you made the first mapping directly from the server.
However, if the received model is nearly complete, you can always customize the "create" of your mapping (You could look for missing observable properties using js hasOwnProperty and adding the missing ones). The last example of the docs in the link so precisely how to add a new observable (in this sample, a computed observable):
var myChildModel = function(data) {
ko.mapping.fromJS(data, {}, this); // this is the view model
this.nameLength = ko.computed(function() { // nameLength is added to the vm
return this.name().length;
}, this);
}
In this sample you could add the condition to create nameLength only if not present on the received data, like this:
if (!data.hasOwnProperty('nameLength')) {
/* add the missing observ. property here */
}
(NOTE: you can also customize the update, if needed).
I have solved it using jQuery extend method by merging the object before mapping. So I only needed one call to the mapping function.
var mergedData = jQuery.extend(true,data,templateStructure);
ko.mapping.fromJS(mergedData, {}, this);
I have been working with ASP.NET but I am fairly new to the ASP.Net MVC 4 with Razor concept. So my question might be basic but I appreciate every help as I couldn't really find a definite answer for days now (Or I am looking for the wrong things). The question is: How do I access a Controller method within my view without using my Index Method?
The scenario:
I have a database that store some values like date, price etc ... (Variables are defined in the Model.
I have a controller thats sets a view index
I have a view that shows Indexpage with the values of my data base.
I want to sum all values of the price colum but dont want to store the result in my db.
In my understanding I access the db via a Method in my Controller class and call this method in my view.
To learn step by step I just defined a fixed value in my controller to see how to show this value in my view.
The code:
Model:
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; } // Amount of an entry
Controller:
public ActionResult Index()
{
return View(db.Amounts.ToList());
}
public ActionResult ShowSumOfAllPrices()
{
//For testing db is not called yet. Query must be defined and result written to a variable within this mehod
ViewBag.Price = 2;
return View();
}
View:
#*testmethod for displaying sumprize (first just wit test result) via controler*#
<table>
<tr>
<td>hallo #ViewBag.Price</td>
</tr>
</table>
The result is not shown as long as I don't define the method content of ShowSumOfAllPrices() (in my controller class) in the index() method.
The question is: Is a result of a method in a view only visible if I define it within my Index() method in my controller or can I write an extra method like I did and call it in my view? It is working if I c&p the logic of ShowSumOfAllPrices() to Index(). But I don't think I need to define everything in my index method. If so, it would be a large and fat method. So as far as I see there are 3 possible ways but not all might be "nice" or even working:
Define everything in the Index() method.
Define other methods but call them in the Index method because it is the only way to display it within my view and not using the model because i dont want to store those data in my db
I can define other methods and directly call them in my view without having a new page but only the result of this method shown under the content of the currend Index Page.
I hope my question is understandable and this question was not asked like mine before.
Define everything in the Index() method.
Controllers are not meant to hold the logic.
Define other methods but call them in the Index method because it is the only way to display it within my view and not using the model because i dont want to store those data in my db
Don't define other methods in the controller itself. Make other classes and then call those methods in the Index() or any suitable controller method. And if you want to display data in the view , then model is the best choice, but you can even store your data in the ViewBag
I can define other methods and directly call them in my view without having a new page but only the result of this method shown under the content of the current Index Page.
If you want to fetch the result of the methods in the same view then this can be the case[might be using same kind of AJAX] but if you want to render other page , then this might be a bad idea.
The best thing you can do is to declare a class for your required function as Single responsibility principle and then use the class to do that operation in the method you want to have results in.You can access the controller methods using AJAX and JQuery, just google it out a bit and you will be your own.
Hope this helps.
I'm currently trying to find a "definitive" solution (meaning : finding a solution that seems efficient a complying with OOP precepts) to a recurring problem I've been experiencing for some time : the problem of shared data in different parts of my code.
Take note that I'm not using any MVC framework anywhere here. I'm just refering to my data class as a Model and to the display class as a View (because its the proper names and have nothing to do with the MVC pattern, people made views & models way before the MVC pattern was "created").
Here's my problem :
Whenever I make an application that uses some quite expanded data (for example a game), I try to separate logic (movements, collisions, etc...) and display in two classes. But then, I stumble upon the problem : how to "bind" the data stored in my logic class with the corresponding display objects in my view class, without duplicating data, references, or other things between the different classes ?
Lets take a basic example :
I have a MyLogicClass, holding a Vector of "EntityData" objects (each with position, sizes, various states, everything to handle the logic of my items)
And I have a MyViewClass, creating and displaying Sprites for each EntityData that are in the MyLogicClass, and make them move after them being updated in the game loop.
The first thing that would come to my mind would be to store inside each data element its corresponding view, thus allowing me to loop throught my Vector to update the items logic then update the views accordingly. But that forces me to hold a MyLogicClass reference inside the MyViewClass, to be sure that I can target the entities data, forcing me to couple the two classes (things that I would prefer not to do).
On the other hand, there's the solution of each Entity having an ID, both in my data model (MyLogicClass's EntityData objects having an ID parameter) and in my View class (Sprites holding a reference to its original entity data ID). But when I want to target a specific entity that forces me to loop for it in my data model, then loop for it again to find the related Sprite in my View. This solution allows me to have loose coupling between my data and my view, but looping through hundreds of elements twice every frame (can happen !) really sounds not performance optimized for me.
I may be giving the whole problem a lot more importance that it should deserve, but I've been stumbling upon that more than one time, and I'd love to have some other views than mine about that.
Do you guys have any advice / solution for such an issue ?
Are there some other data formats / hierarchy that I may not be aware of for such case ?
What I've done is 'link' them together using events and event listeners. I have my "model parts" throw specific events that the "display parts" catch and render/update.
I've found this does let me structure some of my tests by writing testing code that would listener for certain events and error checks it that way. My code is still separated and testable on it's own: I can test my "model" by triggering and making sure the right events with the right values are being thrown. Like-wise, I can write some testing code to throw preset events that can be caught by the "display" to see if it has any issues.
Then once it is all working, I just reuse those same event listeners and link to 'each other'.
Later my "controller" (user input) would manipulate the "model" parts, which would cause events to be thrown to the "display" thus be rendered/updated.
I don't know if this is "correct" or not in terms of following the mvc pattern nor do I really have any formal knowledge on these sorts of things. I'd be interested in someone else's more knowledgeable opinion as well.
I think maybe you have over thought the problem. I do this sometimes.
Your view class has to have some type of link to the model obviously and an event is a great way to do it. Something bare bones here to give you an idea.
// Model class
package
{
class MyModel extends EventDispatcher
{
// you can make them public but that would
// be against some oop practices. so private it is
private var m_position:Vector2D;
MyModel(){}
// one way of doing getters/getters
// example: theModel.SetPosition(something);
public function GetPosition():Vector2D { return m_position; }
public function SetPosition(value:Vector2D):void
{
m_position = value;
ModelChanged();
}
// the other way
// sample: theModel.position = something;
public function get position():Vector2D {return m_position; }
public function set position(value:Vector2D):void
{
m_position = value;
ModelChanged();
}
private function ModelChanged():void
{
dispatchEvent(new Event(Event.CHANGE));
}
}
}
// now for our view.
package
{
class MyView extends Sprite // or whatever
{
private var model:MyModel;
MyView(model:MyModel)
{
this.model = model;
model.addEventListener(Event.CHANGE, handleModelChanged);
// fire off an event to set the initial position.
handleModelChanged(NULL);
}
private function handleModelChanged(evt:Event):void
{
x = model.position.x;
y = model.position.y;
// etc etc etc.
}
}
}
Anyhow you don't need the setters if your going to have the logic in the model file also obviously if nothing outside of the model needs to change it no reason for setters. But you do need the getters.
This decouples the model from the view and you can write any view any way you want and all you have to provide is a handler for when the model has changed. Just expose whatever data your views will need with getters.
You now only have to loop through the models and if one changes it will fire off an event and the views that are listening in will update.
hope I didn't miss anything and that explains what you were wanting.
Edit: I forgot to add, you don't have to have "ModelChanged()" all over the place if your using something like an update function. Just update and when your finished fire off the event.