When I click on an AjaxLink, I would like to have a validation via JavaScript on the client side first (because the LocalStorage is queried) and then depending on the result, further JavaScript calls are made. How can i achieve this?
In a pseudo code it would look like this:
new AjaxLink<>("myId", myModel) {
#Override
public void onClick(AjaxRequestTarget target) {
boolean isCounterValid = target.appendJavaScript(checkCounter()); // i know that this is not possible, therefore pseudo code
if(isCounterValid) {
target.appendJavaScript(someOtherJavaScript());
}
else {
target.appendJavaScript(anotherJavaScript());
}
}
private String checkCounter() {
return "var count = window.localStorage.getItem('myCounter'); return count !== 1;";
}
private String someOtherJavaScript() {
return "change something";
}
private String anotherJavaScript() {
return "change other thing";
}
};
You need to send extra request parameters with the Ajax call when the link is clicked. For that you should override updateAjaxAttributes(AjaxRequestAttributes attributes) method of AjaxLink:
#Override
protected void updateAjaxAttributes(AjaxRequestAttributes attributes)
{
attributes.getDynamicExtraParameters().add("var count = window.localStorage.getItem('myCounter'); return [{\"name\":\"count\", \"value\": count}]");
}
This way inside AjaxLink#onClick() you can read the count via:
int count = getRequest().getRequestParameters().getParameterValue("count").toInt();
AJAX components and behaviors can customize AJAX attributes overriding updateAjaxAttributes and using a custom implementation of AjaxCallListener which exposes different method to hook into the AJAX request cycle. In you case you could use AjaxCallListener#getBeforeSendHandler.
For a full introduction to this topic (with examples) see user guide:
https://ci.apache.org/projects/wicket/guide/8.x/single.html#_ajax_request_attributes_and_call_listeners
Related
I have an MVC application in which I have to update the view with the current value of a stream.
In the model I have this method:
public Observable<Integer> getStreamInstance(){
if(stream == null){
this.stream = Observable.create((Subscriber<? super Integer> subscriber) -> {
new HeartbeatStream(frequence,subscriber).start();
});
}
return stream;
}
which I use in the controller to get the stream. Then, in the controller I have these two methods:
public void start(){
this.sb = stream.subscribe((Integer v) -> {
view.updateCurrValue(v);
});
}
public void stop(){
this.sb.unsubscribe();
}
With the start method I simply update a label in the view with the current value.
This works fine until I try to stop the updating with the unsubscribing; infact, when I press the button "stop" in the view, the label keeps updating with the current value and, if I press "start" again, the label shows the values from two different streams, the one that I first created with the first "start" and the second that seems has been created with the second pressing of "start".
Where am I wrong?
EDIT:
public class HeartbeatStream extends Thread{
private Subscriber<? super Integer> subscriber;
private int frequence;
private HeartbeatSensor sensor;
public HeartbeatStream(int freq, Subscriber<? super Integer> subscriber){
this.frequence = freq;
this.subscriber = subscriber;
sensor = new HeartbeatSensor();
}
public void run(){
while(true){
try {
subscriber.onNext(sensor.getCurrentValue());
Thread.sleep(frequence);
} catch (Exception e) {
subscriber.onError(e);
}
}
}
This is the HeartbeatStream class. HeartbeatSensor is a class that periodically generates a value that simulates the heartbeat frequence.
I'm guessing you tried to periodically signal some event that triggers the screen update. There is an operator for that:
Observable<Long> timer = Observable.interval(period, TimeUnit.MILLISECONDS,
AndroidSchedulers.mainThread());
SerialSubscription serial = new SerialSubscription();
public void start() {
serial.set(timer.subscribe(v -> view.updateCurrValue(v)));
}
public void stop() {
serial.set(Subscriptions.unsubscribed());
}
public void onDestroy() {
serial.unsubscribe();
}
Observable by design unsubscribe your observer once that all items are emitted and onComplete callback is invoked.
Look this example https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/creating/ObservableSubscription.java
I guess you're not handling the unsubscribe - although I can't see what's going on in your HeartbeatStream class.
If you're creating an Observable with Observable.create then you need to handle unsubscribing explicitly with subscriber.isUnsubscribed().
Where possible use some of the utility methods to create an Observable - they handle this all for you eg Observable.just() or Observable.from().
If this doesn't help, please post your HeartbeatStream class.
See the the docs for more details:
https://github.com/ReactiveX/RxJava/wiki/Creating-Observables
https://github.com/ReactiveX/RxJava/wiki/Async-Operators
While questions of this sort have been frequently asked, I think I have a more specific constraint that makes the problem a little more interesting. I am writing a client-side application in Dart using an MVC pattern. My goal is simple: listen for clicks on a button, trigger an async request to a back-end API, and present that data to the user.
Minimally, I have one each of a model, view, and controller class. The model class implements methods to make requests and bundle up the data it receives. The view class has the DOM subtree of interest as a field and implements methods to manipulate the elements therein. The controller has a single instance each of the model and view classes as its fields and registers event handlers on the elements of the view. The controller's event handlers fire off calls to the model to make requests and return data, which will then be passed to the view for rendering.
The issue arises when I attempt to capture the incoming data from the async request into an instance variable of the model. I'd like to keep everything nicely encapsulated (that's why I'm using Dart in the first place), and I'd like to avoid using a global variable to hold the data that comes from the async request. A minimal example of my current layout looks something like below. I've made all of the fields and methods public here for clarity's sake.
// view.dart
class FooView {
// The root element of the view with which we're concerned.
static final Element root = querySelector('#thisView');
FooView() { init(); }
void init() { root.hidden = false; }
// Appends the new data into an unordered list.
void update(List<Map<String,String>> list) {
UListElement container = root.querySelector('ul#dataContainer');
container
..hidden = true
..children.clear();
for ( Map<String,String> item in list ) {
container.append(new LIElement()
..id = item['id']
..text = item['text']
);
container.hidden = false;
}
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
List<Map<String,String>> dataList;
// Makes async request, returning data to caller.
List<Map<String,String>> getData() {
HttpRequest
.getString('example.com/api/endpoint')
.then( (String data) {
dataList = JSON.decode(data);
});
return dataList;
}
}
// controller.dart
class FooController {
FooModel model;
FooView view;
FooController() {
model = new FooModel;
view = new FooView;
}
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = view.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
view.update(model.getData());
});
}
}
The errors I'm seeing involve the model.dataList field coming up null at the end of all of this. My first blush is that I do not understand scoping of callback functions. The way I first understood it, the callback would handle the request's data when it arrived and just set the instance variable when it was ready. Perhaps the instance variable is aliased and modified within the scope of the callback, but the variable I want to return is never touched.
I have thought about passing a Future object to a method of the view, which will then just do the processing itself and add the elements to the DOM as a side effect. That technique would break my MVC design (even more than it's broken now in this minimal working example).
It is also very possible that I am using asynchronous programming completely incorrectly. Thinking more on this, my async call is useless because I basically make a blocking call to view.update() in the controller when the event fires. Maybe I should pass a request Future to the controller, and fire the request's then() method from there when the event handler is triggered.
In Dart, in what scope do callback functions reside, and how can I get data out of them with minimal side effects and maximal encapsulation?
N.B. I hate to belabor this oft-discussed question, but I have read previous answers to similar questions to no avail.
The getData method initiates the asynchronous HTTP request then immediately returns before having received/parsed the response. That is why model.datalist is null.
To make this work with minimal effort, you can make getData synchronous:
(note: I changed the dataList type, just to make it work with the sample JSON service http://ip.jsontest.com/)
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
Map<String, String> dataList;
// Makes async request, returning data to caller.
Map<String, String> getData() {
var request = new HttpRequest()
..open('GET', 'http://ip.jsontest.com/', async: false)
..send();
dataList = JSON.decode(request.responseText);
return dataList;
}
}
Though this may violate your objective, I agree with your concerns re: blocking call and would personally consider keeping the HTTP request asynchronous and making getData return a new future that references your model class or parsed data. Something like:
// model.dart
class FooModel {
// Instance variable to hold processed data from the async request.
Map<String,String> dataList;
// Makes async request, returning data to caller.
Future<Map<String, String>> getData() {
return HttpRequest
.getString('http://ip.jsontest.com/')
.then( (String data) {
dataList = JSON.decode(data);
return dataList;
});
}
}
and in the controller:
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = FooView.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
model.getData().then((Map<String, String> dataList) {
view.update(dataList);
});
});
}
You return datalist in getData before the HttpRequest has returned.
// Makes async request, returning data to caller.
List<Map<String,String>> getData() {
return HttpRequest // <== modified
.getString('example.com/api/endpoint')
.then( (String data) {
return JSON.decode(data); // <== modified
});
// return dataList; // <== modified
void registerHandlers() {
// When this button is clicked, the view is updated with data from the model.
ButtonElement myButton = view.root.querySelector('#myButton');
myButton.onClick.listen( (Event e) {
model.getData().then((data) => view.update(data)); // <== modified
});
}
You can use Stream to make your design loosely coupled and asynchronous:
class ModelChange {...}
class ViewChange {...}
abstract class Bindable<EventType> {
Stream<EventType> get updateNotification;
Stream<EventType> controllerEvents;
}
class Model implements Bindable<ModelChange> {
Stream<ModelChange> controllerEvents;
Stream<ModelChange> get updateNotification => ...
}
class View implements Bindable<ViewChange> {
Stream<ViewChange> controllerEvents;
Stream<ViewChange> get updateNotification => ...
}
class Controller {
final StreamController<ViewChange> viewChange = new StreamController();
final StreamController<ModelChange> modelChange = new StreamController();
Controller.bind(Bindable model, Bindable view) {
view.controllerEvents = viewChange.stream;
model.controllerEvents = modelChange.stream;
view.updateNotification.forEach((ViewChange vs) {
modelChange.add(onViewChange(vs));
});
model.updateNotification.forEach((ModelChange mc) {
viewChange.add(onModelChange(mc));
});
}
ModelChange onViewChange(ViewChange vc) => ...
ViewChange onModelChange(ModelChange mc) => ...
}
I have a form with many input-fields and need to handle a change to any of those input-fields; so I add a AjaxEventBehavior to the form, like:
Form<MyX> myForm = new Form<>("X", getModel());
myForm.add(new AjaxEventBehavior("onchange") {
#Override
protected void onEvent(AjaxRequestTarget target) {
handleFormChange(...);
}
});
The method handleFormChange gets called everytime I change some content in the input-fields of the form. But the model is not getting updated with the new value of the changed input-field of the form.
How can I get thoose model-updates? I tried AjaxFormComponentUpdatingBehavior. It updates the model, but I cannot use it for forms, just for FormComponents.
Does anybody has an ideas how to handle that? TIA!
With AjaxFormSubmitBehavior you can submit the whole form on each change.
First for on change use the dedicated OnChangeAjaxBehavior.
Then you can use the Iterator of the form to get all children and add then add the OnChangeAjaxBehavior to all FormComponents which will call your handleFormChange() on every change like this:
for (Iterator it = form.iterator(); it.hasNext();) {
Object o = it.next();
if (o instanceof FormComponent) {
((FormComponent) o).add(new OnChangeAjaxBehavior() {
#Override
protected void onUpdate(AjaxRequestTarget target) {
handleFormChange(...);
}
});
}
}
I'm fairly new to Wicket but I've already run into a very strange problem.
I'm creating a page with a pretty basic search form and a results table (a DataView) which is initially empty. When the user enters data into the fields and clicks "Search", the app calls some backend services which are then used to populate the DataView.
However the user has to click "Search" twice for the data to be displayed.
I finally tracked this down, and it's because Wicket is using zero for the number of items to be displayed for the first "Search" click. At the second click, the rows have already been added and Wicket has already calculated the proper number of rows to display, so it decides it will show the data.
In AbstractPageableView.getItemModels(), the size of the results to display is initially zero, because I don't load the table with any initial data probably.
I got around this problem by loading the DataView with empty rows on page load. This seems to trick the DataView into using the displaying the data for the first "Search" click.
My question is: am I doing this right? Is there another repeater that is better for this task? Is this a bug or something?
Finally cracked it: it was because I was loading the data in my data provider only in the iterator() method, and the data provider's size() method is usually called before the iterator() method is. I should have been loading the data in its own method and calling that method from iterator() and size(). Doing that fixed it.
Data Provider before (Splc is the DTO):
SearchResultsDataProvider implements IDataProvider<Splc> {
/**
* The list of search results
*/
private List<Splc> models;
#Override
public void detach() {
// Do nothing
}
#Override
public Iterator<Splc> iterator(int first, int count) {
// load the data into the list of models
models = service.getSplcModels();
return models.subList(....).iterator();
}
#Override
public IModel<Splc> model(Splc object) {
return new Model<Splc>(object);
}
#Override
public int size() {
return models.size();
}
}
Data Provider after:
SearchResultsDataProvider implements IDataProvider<Splc> {
private List<Splc> getModels() {
// load the data into the list of models
return service.getSplcModels();
}
#Override
public void detach() {
// Do nothing
}
#Override
public Iterator<Splc> iterator(int first, int count) {
return getModels().subList(....).iterator();
}
#Override
public IModel<Splc> model(Splc object) {
return new Model<Splc>(object);
}
#Override
public int size() {
return getModels().size();
}
}
i'm trying to wrap my head around how to enterprise up my code: taking a simple routine and splitting it up into 5 or 6 methods in 3 or 4 classes.
i quickly came up three simple examples of code how i currently write it. Could someone please convert these into an MVC/MVP obfuscated version?
Example 1: The last name is mandatory. Color the text box red if nothing is entered. Color it green if stuff is entered:
private void txtLastname_TextChanged(object sender, EventArgs e)
{
//Lastname mandatory.
//Color pinkish if nothing entered. Greenish if entered.
if (txtLastname.Text.Trim() == "")
{
//Lastname is required, color pinkish
txtLastname.BackColor = ControlBad;
}
else
{
//Lastname entered, remove the coloring
txtLastname.BackColor = ControlGood;
}
}
Example 2: The first name is optional, but try to get it. We'll add a bluish tint to this "try to get" field:
private void txtFirstname_TextChanged(object sender, EventArgs e)
{
//Firstname can be blank.
//Hint them that they should *try* to get it with a bluish color.
//If they do enter stuff: it better be not all spaces.
if (txtFirstname.Text == "")
{
//Nothing there, hint it blue
txtFirstname.BackColor = ControlRequired;
}
else if (txtFirstname.Text.Trim() == "")
{
//They entered spaces - bad user!
txtFirstname.BackColor = ControlBad;
}
else
{
//Entered stuff, remove coloring
txtFirstname.BackColor = SystemColors.Window;
}
}
Example 3 The age is totally optional. If an age is entered, it better be valid:
private void txtAge_TextChanged(object sender, EventArgs e)
{
//Age is optional, but if entered it better be valid
int nAge = 0;
if (Int32.TryParse(txtAge.Text, out nAge))
{
//Valid integer entered
if (nAge < 0)
{
//Negative age? i don't think so
txtAge.BackColor = ControlBad;
}
else
{
//Valid age entered, remove coloring
txtAge.BackColor = SystemColors.Window;
}
}
else
{
//Whatever is in there: it's *not* a valid integer,
if (txtAge.Text == "")
{
//Blank is okay
txtAge.BackColor = SystemColors.Window;
}
else
{
//Not a valid age, bad user
txtAge.BackColor = ControlBad;
}
}
}
Every time i see MVC code, it looks almost like random splitting of code into different methods, classes, and files. i've not been able to determine a reason or pattern to their madness. Without any understanding of they why it's being one some way, it makes no sense. And using the words model, view, controller and presenter, like i'm supposed to know what that means, doesn't help.
The model is your data.
The view shows data on screen.
The controller is used to carry out
the users actions
And oranges taste orangy.
Here's my attempt at splitting things up in order to make the code more difficult to follow. Is this anywhere close to MVC?
private void txtFirstname_TextChanged(object sender, EventArgs e)
{
FirstnameTextChangedHandler(sender, e);
}
private void FirstnameTextChangedHandler(sender, e)
{
string firstname = GetFirstname();
Color firstnameTextBoxColor = GetFirstnameTextBoxColor(firstname);
SetFirstNameTextBoxColor(firstnameTextBoxColor);
}
private string GetFirstname()
{
return txtFirstname.Text;
}
private Color GetFirstnameTextBoxColor(string firstname)
{
//Firstname can be blank.
//Hint them that they should *try* to get it with a bluish color.
//If they do enter stuff: it better be not all spaces.
if (firstname == "")
{
//Nothing there, hint it blue
return GetControlRequiredColor();
}
else if (firstname.Trim() == "")
{
//They entered spaces - bad user!
return GetControlBadColor();
}
else
{
//Entered stuff, remove coloring
return GetControlDefaultColor();
}
}
private Color GetControlRequiredColor()
{
return ControlRequired;
}
private Color GetControlBadColor()
{
return ControlBad;
}
private Color GetControlGoodColor()
{
return ControlGood;
}
//am i doin it rite
i've obfuscated the code, but it's still altogether. The next step in the MVC obfuscation, i gather, is to hide the code in 3 or 4 different files.
It's that next step that i don't understand. What is the logical separation of which functions are moved into what other classes? Can someone translate my 3 simple examples above into full fledged MVC obfuscation?
Edit: Not ASP/ASP.NET/Online. Pretend it's on a desktop, handheld, surface, kiosk. And pretend it's language agnostic.
The purpose of MVC/MVP patterns is not obfuscation, but separation of concerns. Obfuscation is to (conceal the) intended meaning in communication, making communication confusing, intentionally ambiguous, and more difficult to interpret: ref. The use of patterns is to make the code cleaner and more understandable. I suggest you start out by reading the wikipedia entries on MVC and MVP.
Both patterns are ways of structuring your code so that your application is broken up into elements that carry out specific purposes that have clearly defined interaction boundaries. Rather than having code that specifically addresses business concerns, input/output handling, and presentation throughout the various classes of the application, these concerns are separated and isolated in the various architectural components. These architectural elements are insulated from one another by the interaction boundaries (interfaces) making them more independent of one another and easier to modify without affect the application as a whole.
The main idea I have when implementing MVC for Windows Forms is that I want to have unit tests for my model and my controller. In order to achieve that, my controller should not know anything about the views using it, and so any notifications that should be handled on UI level are implemented as events. In your example, my controller would look something like this:
class Controller
{
// This is the model we are operating on
private Model model_;
public enum Status
{
Normal,
Required,
Good,
Bad
}
public delegate void FirstNameStatusChangedDelegate(Status newStatus);
public event FirstNameStatusChangedDelegate FirstNameStatusChangedEvent;
public string FirstName
{
get { return model_.FirstName; }
set
{
if (value == "")
RaiseFirstNameStatusChanged(Status.Required);
else if ( value.Trim() == "" )
RaiseFirstNameStatusChanged(Status.Bad);
else
{
model_.FirstName = value;
RaiseFirstNameStatusChanged(Status.Normal);
}
}
}
private void RaiseFirstNameStatusChanged(Status newStatus)
{
if ( FirstNameStatusChangedEvent != null )
FirstNameStatusChangedEvent(newStatus);
}
}
And the view would provide handlers for the FirstNameStatusChanged event:
class View : Form
{
private Controller controller_;
private static readonly Dictionary<Controller.Status, Color> statusColors_ = new Dictionary<Controller.Status, Color>
{
{Controller.Status.Normal, SystemColors.Window},
{Controller.Status.Required, ControlRequired},
{Controller.Status.Good, ControlGood},
{Controller.Status.Bad, ControlRed}
};
public View(Controller controller)
{
InitializeComponent();
controller_ = controller;
contoller_.FirstNameStatusChangedEvent += OnFirstNameStatusChanged;
}
private void txtFirstname_TextChanged(object sender, EventArgs e)
{ controller_.FirstName = txtFirstName.Text; }
private void OnFirstNameStatusChanged(Controller.Status newStatus)
{ txtFirstName.BackColor = statusColors_[newStatus]; }
}
Most of what you doing in your code belongs to the Controller class since it describes the the logic. Your View should just describe UI and give easy access to UI components. Model class should describe your data model.
The idea is simple: Controller does everything, but it has to know about the View and the Model. For example as View is initialized, Controller sets up all the logic ( kinda what you already doing). As Model is assigned to the Controller - it sets the values into appropriate UI controls and does the same to retrieve data and return is as Model.
So basically you give your data model class to the controller, it does the editing and returns your data as model class again.
It would be very hard to follow MVC in classic ASP.NET if possible, so I will reply based on MVP.
On your first example, you are trying to do a validation. Validating a surname is the responsibility of Presenter. Showing the field red is the responsibility of View. So, your view class would be like this:
private void Page_Load()
{
this._presenter = new Presenter();
}
private void txtLastname_TextChanged(object sender, EventArgs e)
{
txtLastName.BackColor = presenter.IsLastnameValid(txtLastName.Text) ?
ControlGood : ControlBad;
}
And your presenter class would be something like this:
public Presenter()
{
public bool IsLastNameValid(string lastname)
{
return string.IsNullOrEmpty(lastname);
}
}
Last name is your model here.
Please note that I prepared this classes only for showing how would you form an MVP structure. In real world, there are lots of better ways to do validation. Normally you would use this approach for your business instead of validation.
Ian,
If you want the controls to validate immediately, you need to use javascript or jQuery. This is also true for classic ASP.NET. Since you are using Code Behind methods, I assume that your validation waits for a postback.
The following examples are from the NerdDinner project. NerdDinner is an open source project that serves as an example of ASP.NET MVC architecture. The authors have graciously provided a tutorial with it, available at http://nerddinnerbook.s3.amazonaws.com/Intro.htm
When a form is submitted in ASP.NET MVC, it enters the corresponding controller as a FormCollection object:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
try
{
UpdateModel(dinner);
dinnerRepository.Save();
}
catch
{
ModelState.AddModelErrors(dinner.GetRuleViolations())
}
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
UpdateModel takes the form values and attempts to stuff them into the dinner object. The dinner object looks like this:
public partial class Dinner {
public bool IsValid {
get { return (GetRuleViolations().Count() == 0); }
}
public IEnumerable<RuleViolation> GetRuleViolations() {
yield break;
}
public IEnumerable<RuleViolation> GetRuleViolations() {
if (String.IsNullOrEmpty(Title))
yield return new RuleViolation("Title is required", "Title");
if (String.IsNullOrEmpty(Description))
yield return new RuleViolation("Description is required", "Description");
if (String.IsNullOrEmpty(HostedBy))
yield return new RuleViolation("HostedBy is required", "HostedBy");
if (String.IsNullOrEmpty(Address))
yield return new RuleViolation("Address is required", "Address");
if (String.IsNullOrEmpty(Country))
yield return new RuleViolation("Country is required", "Address");
if (String.IsNullOrEmpty(ContactPhone))
yield return new RuleViolation("Phone# is required", "ContactPhone");
if (!PhoneValidator.IsValidNumber(ContactPhone, Country))
yield return new RuleViolation("Phone# does not match country", "ContactPhone");
yield break;
}
partial void OnValidate(ChangeAction action) {
if (!IsValid)
throw new ApplicationException("Rule violations prevent saving");
}
}
Notice the IsValid method and the RuleViolations enumerator. If everything is set up properly, all you have to do is define your validations in here, and ASP.NET MVC will take care of the rest for you.
The final validated result looks like this:
I encourage you to get the NerdDinner application and tutorial at http://nerddinner.codeplex.com/