Using modal in CakePHP3 (or: Javascript in Controllers) - javascript

I have a standard form, generated via cake/bake.
When the form is send, my controller checks a (trivial) condition,
on condition A it just saves the data (patchEntity($foo,
$this->request->getData())
on condition B it should call a JS warning, and then save the data.
My favorite warning would be a Bootstrap4 Modal, but how can I call a modal in a controller?
I know this kind of violates the idea of MVC. So, alternative ideas are welcome.
The only solution I see atm is that I redirect to a new action which just opens a modal.

Given that the condition can only be evaluated on the server side, you could for example issue an AJAX request, either before sending the form, or for sending the form itself, and then respond with corresponding information that you can evaluate in your AJAX response handler to decide whether you need to show a modal.
You should then probably (re)send the form with an additional flag that indicates that the consecutive request stems from the warning dialog, and that you can go on with saving the data.

What is the problem in using flash component, like so :-
$this->Flash->error(__('This is the warning.'));
Remember to add $this->loadComponent('Flash'); in the initialize function of your controller, like so:-
class ArticlesController extends AppController{
public function initialize(){
parent::initialize();
$this->loadComponent('Flash'); // Include the FlashComponent
}
// Rest of your code here...
}

Related

Inertia Manual Share State Lazily Inside Controller not Working

I'm going crazy because of this one, I have this address form in a very nested component and a route to validate the form input data. In the controller, I want to return back to the same page but share the form data to be able to fetch it in a parent component. I'm trying to follow Inertia DOCs to lazily share the data to be available to all components but for some reason this isn't working!
1- I'm submitting the form:
const submitAddressCheck = () => {
shippingDetailsForm.post(
route("cart.checkaddress", [props.webshop_slug]),
{}
);
};
2- The form gets validated as expected but it doesn't share the data globally to all components.
CartController.php
public function checkaddress(StoreAddressCheckRequest $request)
{
Inertia::share(
'testing',
fn ($request) => $request
? $request
: null
);
return redirect()->back();
}
Once I submit the form it gets validated and that's it, no new props passed, the data isn't being shared to my parent component or anything. Am I missing something?
Inertia::share() will not persist any data passed between requests. So if you share data and then redirect to another route, then your shared data will not be passed.
You are probably looking for Flash messages. With flash messages you use the with() method when redirecting to show errors, success messages, anything you like. Make sure you follow the documentation and add the code to the HandleInertiaRequests middleware.
When it is time to redirect, you do something like this:
return redirect()->back()->with('testing', $request->all());

How to handle ajax in knockout viewmodels?

I am using knockout in my project. I have multiple viewmodel, each viewmodel have its own save function implemented in it. Now whenever user clicks on save button the viewmodel data post to the server, i want to block the save button until the response came back from server.
Currently i am handling this by creating an extra observable property saving in each viewmodel. So when user click over the save button i am setting saving observable to true and in callback i am setting it to false. And i have bind this saving property with the button using knockout disable binding.
But i feel that this approach is not good and it contains the following big drawbacks:
For this i have to add an extra property in each viewmodel.
I have to add multiple line of code like setting it to true and again set it to false.
The approach is not centralize, the code for this approach is scattered.
So i want to know is there any other better way to handle this, a plugin or some standard way ??
Edit
Just to clarify, my question has nothing to do with asp.net postback, the question is how i can handle efficiently the ajax, like block the save button, displaying the response message etc
??
This is generally what makes a viewmodel a viewmodel. In a pattern like MVC, your controller shouldn't really have any idea what your view looks like, what controls it has, or what it's state is, and your model only contains data for the view to model. In an MVVM pattern, as knockout is, your viewModel actually does have knowledge of the current states of controls on the view. This isn't to say your viewmodel should directly update the view, but it usually will contain properties that are bound to states of the view. Things like SaveButtonEnabled or IsSavingData or even things like StatusLabelColor are accepted in a viewmodel.
Perhaps use $.ajaxSetup(). You call this in your document ready function.
$.ajaxSetup({
beforeSend: function(jqXHR)
{
//this will be called before every
//ajax call in your program
//so perhaps, increment an observable viewmodel variable
//representing the number of outstanding requests
//if this variable is > 0 then disable
//your button
},
complete: function(jqXHR)
{
//this will be called after every
//call returns
//decrement your variable here
//if variable is zero, then enable button
}
});
I'd recommend you take a look at http://durandaljs.com/, a framework using Knockout and has some great data patterns, even if you don't use it directly.

How do I perform an action before any view(or partial) is rendered?

My problem is simple. I want to know if there is a method(or something) that is automatically called by default(by ASP.Net engine) before any view(or partial) is rendered. I like to intercept it to perform an action, e.g generate a random number.
I will explain my scenario in case of somebody have a better idea.
My app's views and partials renders elements with an id pattern like this: Model_Id. In some cases, when user brings up a modal window with a view that repeats the id of any element of the main window, my jquery selectors get confused. I've already create custom helpers to do that behavior, so I thought about generate random number(and store it on session) and concat it in the id, to get something like Model_Id_1234 or 1234_Model_Id.
If there is a better way, it will be really nice to know.
you could write a custom action filter to allow you to intercept ahead of the action performing. This would then be called using the method:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// do your pre action display stuff here!!
// if the code is added to basecontroller -
// also optionally defer back to base.OnActionExecuting(filterContext);
base.OnActionExecuting(filterContext);
}
I'll add to the answer with further detail as literally in transit just now.
See this post on MSDN, it covers the controller pipeline for MVC.
[Edit] - in response to comment, see also this SO answer: Calling the Session before any Controller Action is run in MVC. In effect, in this example, we don't create an actionfilter, we only override the OnActionExecuting inside the base controller.

How to redirect to different controller?

I have an application in ASP.MVC. The requirement is that I select a person from a list of people and click 'Info' and it should load the details of the person in that page. I have the Info controller and everything works fine if I go to the Info page from a different controller. In the page I am trying to make it work with JavaScript and it doesn't seem to take me to the desired page but to a different controller.
I have a ToDoList controller and in the .cshtml I have this code on click of the Info link.
function DoInfo#(i.ToString())() {
$("#sessionid").val("#Model.cSessionId[i]");
alert("hey");
$("#PageController").val(66);
$("#formID").submit();
}
I go to the ToDoList controller to do the redirection like this
if (viewModel.PageController == 66)
{
pass = new PassingData();
pass.personid = TSSessionService.ReadPersonId(viewModel.SessionId);
TempData["pass"] = pass;
return RedirectToAction("Index", "Info");
}
It never goes there and instead goes to a different controller. I cannot seem to find how they are linked and why is it not going back to controller where the Info link button is i.e. back to the ToDoList controller.
Let me know if it is not clear and I will try to explain again and I will give any other details.
I guess I'm confused as to why you are doing this as a combination of form and JavaScript. Are there other properties that you need to pass along that you are not posting above? Why do you need to use JavaScript to do this if you are just returning a new view?
You indicate in your post that when a person is selected from a list you need to go to a controller and display a view. This seems fairly straightforward, and I would like to suggest simplifying the problem.
Start with this: change your link to not use a form or JavaScript. Just make it a link. If it is text, you can use #Html.ActionLink() and even pass in the parameters you need.
If you're not displaying text, just use #Url.ActionLink() in your href property of the anchor you're wrapping your element with. Both of these allow you to leverage routing to ensure the correct path is being constructed.
If the controller that you are trying to get to has access to whatever TSSessionService is, then you don't need to pass through the TempData["pass"] you are trying to push through, so it makes it cleaner in that way as well.
If you do need to submit a more complicated value set, I would recommend coming up with a generic .click() event handler in jQuery that can respond to any of the clicks, bound by a common class name. You can use a data-val attribute in your link and read from $(this).attr('data-val') in your handler to store/fetch other important info. This allows you to more easily build up an object to POST to a controller.
Hope this helps some, but if I'm missing a critical point then please update the question above.

JSON object from ASP.NET controller to view

I have a situation where a when a web page is accessed a controller action runs which retrieves the data for that page based on a user selection. I am attempting to send the data back to the page as a JSON object, however, the data opens up as one large string in an HTML page. The controller action, in a nutshell, looks like the following snippet:
Public JsonResult MyMethod(string userSelection)
{
string userData = (string) Data;
return Json(userData, “text”, JsonRequestBehavior.AllowGet);
}
I first tried to use the JQuery $.getJson() method but I think this is wrong as I believe it issues another call to the action method for the data, which is not what I want to do. What I want is to access the JSON object in JavaScript code so I can use the property data to populate fields on the web page. The basic question is what must I do in my JavaScript to receive the JSON object when the page is first rendered? I apologize if I am missing something fundamental; this is my first try.
I still had no luck today but when I left work I came up with a strategy walking to my car. A user makes a selection from a page that presents a list prior to entering the page on which I cannot figure out how to work with JsonResult. Part of the problem is the user selection contains a link that calls the controller/action that returns the JsonResult which conflicts with using $.getJson() within the page where I want to work with JsonResult. So here is my strategy: When the user makes the selection that brings them to the (problematic) page, I will call a controller/action that strictly works with (ASP) ViewData, and use the ViewData to initially present that page. Once on the page, the user can change the selection -- I will handle this with a JavaScript event that uses a $.getJason() call to a different controller/action method that works with (ASP) JsonResult. After I try this strategy I shall post my results for whomever is interested.
You want parseJSON not getJSON
http://api.jquery.com/jQuery.parseJSON/
Edit - Oh wait you are pointing your browser at the JsonResult as if it was an ActionResult? That is not going to work.
Render a proper view, and use getJSON to call the JsonResult action.
getJSON is what you are looking for. Call that on the DOM ready event which will executes once the DOM finishes loading.
$(function(){
//This code will be executed on the DOM ready ( when the page is loaded)
$.getJSON("YourControllerName/MyMethod?userSelection=someValue",function(data){
alert(data.FirstName);
alert(data.AnotherPropertyName);
});
});
getJSON is a shorthand of jQuery ajax method with datatype set as json
Assuming your JSON data you are retuning is something like this
{
"FirstName": "Scott",
"AnotherPropertyName": "SomeValue"
}
To return data like above, change your Action method like this
public JsonResult MyMethod(string userSelection)
{
var result=new { FirstName="Scott", AnotherPropertyName="Great"};
return Json(result,JsonRequestBehavior.AllowGet);
}

Categories