javascript mvc and ajax form submitting - javascript

I just started to investigate mvc on javascript client side (JavaScript MVC). Everything looked great until I got to form submitting :) View part won't do it, that's simple. Event is attached in Controller, so Controller is good place to validate form data, but I'm not sure I want my Controller to know specific server address (were to post my form), so would be great to have a method in Model, but then I don't want my Model to know about my Form (which is actually html structure...).
Well, what do I miss about MVC conception? I am also not sure I want to serialize my form in Controller and then pass it as parameter to my Model. For now, the only option I see to make Model independent is to have JavaScript structure (entity), which will be filled by controller (based on form data) and will be passed to the Model method to be saved on server. Very smplified code:
Info = {
name,
address,
// 15 more properties
...
}
InfoController = {
...
onFormSubmit: function() {
...
info.name = document.getElementById("info-name").value;
info.adress = document.getElementById("info-address").value;
...
InfoModel.save( info );
}
}
InfoModel = {
...
save: function( info ) {
// here some code to setialize info object
// send it to server
...
}
}
But it makes my code too complicated (comparing to simple form serizlization by some side frameworks and just sending it..). What's the right choice?

Just answering my own question. Short answer - yes, I was right with my assumptions ;)
I took a look at JavaScriptMVC, and noticed one simple thing I missed, a simple function can be developed which will create javascript object based on form (they have function called formParams which performs this type of converting). This way my controller is simplified:
InfoController = {
...
onFormSubmit: function() {
...
var info = $infoForm.formParams();
InfoModel.save( info );
}
}
Now it does not look that complicated, and its advantage is that there is one place (model) which knows how to save data (validation; url to send; some other stuff like add this entity to client side 'storage'; firing an event that something new is going to be created; whatever else according to our needs), and if I have one more place, or control flow to perform this operation again I won't write this code again, and it does not depend on presentation (is it form, or just set of inputs, wizard etc.). Also Model becomes quite reusable.
Actually before using this approach we had something similar, but it was not that structured (among different presentations for my application which can run javascript).

Related

Blazor server side problem share javascript code

I'm developing my project with Blazor Server-side.
While I develop, I used javascript code to implement things that hard to implement by C#.
However, I'm facing something weird situation. (I guess it is problem for javascript)
Suppose there are 2 users(A, B). When 'A' user do some action that call javascript code, if 'B' user into same page, 'A' users action affects to 'B' user.
I implemented web page that have 3d scene with threejs. As I explained above, when User 'A' move some object with mouse event(mousemove, mousedown..), if User 'B' accesses the same page, 3d objects of B are moved to the location where User 'A' moved.
Originally, when user access to web page I developed, 3d objects's position should be 0,0,0.
My Guess
I don't use prototype or class(use variable and functions globally. I'm new to javascript.. )
Javascript runs on server-side(share resources??, If then, how can I solve it)
I'm guessing the javascript would be problem, but if you have any other opinions, would you please share?
Edited
I've solved this problem using DotNetObjectReference.Create(this);
C#
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//send created instance to javascript
var dotNetObjRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("SetObjectRef", dotNetObjRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public async Task enableSomething(bool bEnable)
{
var something = bEnable;
}
//== before edit
//[JSInvokable]
//public static async Task enableSomethingStatic(bool bEnable)
//{
// var something = bEnable;
//}
Javascript
var objectRef;
function SetObjectRef(ref) {
objectRef = ref;
}
//call c# function
objectRef.invokeMethodAsync("enableSomething", true);
It was problem of 'static' method as I guessed.
If you declare C# method called from javascript as 'static' and this method changes something of UI variable, this method can affect another users.
So I create instance of current page and send it javascript and when I need to call C# methods from javascript, I call methods using created instance.
Is there any problem or issue, please share it.
Sorry for my bad English.
JavaScript runs client side only. I don't see how two windows, let alone two users, would share data.
Almost for sure, the problem is that you are injecting a singleton service-- which means the server will use one instance for all users.
If so, you have two choices:
(1) add logic to your singleton service to incorporate users. (For example, a dictionary with UserID/Property name for key, and a column for Value)
(2) go to Startup.cs and change the suspect singleton service to .AddScoped(), which will create a new instance for each user.
For right now, I think the latter solution will solve your problem immediately. However, don't underestimate the value of Singletons-- they'll be very useful for other things.

Using PHP/JS to perform actions

to help teach myself PHP I've tasked myself with updating old mysql_* code with PDO.
This has been going great, and as I've been learning I've been able to greatly reduce the amount of code. However my research has ran into a brick wall in a particular area.
Currently, we have it so projects are recorded in a list view, with a set of 'actions/options' for each project. Each of these actions links to a PHP file which runs a small amount of code then sends you back to the list view.
Here is an example:
function projectComplete(id) {
location.href = "complete.php?id=" + id;
}
<button type="button" class="projectComplete" onclick="projectComplete('<?= htmlentities($row['projectid']); ?>')"></button>
The complete.php file simply contains an SQL update query that sets a column in the record a completed state of '1'.
I originally wanted to ask the question 'what is the best practice for handling this type of interaction' however that may attract opinion based answers which I read is not allowed here.
Instead I will phrase it like this: Is there a way of having all of these 'actions' run in the same page? (ideally able to use buttons rather than forms, due to difficulty in layout styling of forms)
I know that if it used forms, I could simply name each form's submit button differently then run an if statement (the only issue would be passing the id, but I'm sure I could figure that out e.g.
if (isset($_POST['exampleAction'])) { Run the code.. }
Any links to guides/tutorials/similar questions etc would be very much appreciated. As previously stated, I'm self-learning PHP - I know very few 'best practices' and would like to learn more.
One thing you could consider is an MVC pattern, where a page call will run some function based on some parameters. A full-blown MVC framework is probably more than you need for this project, but mimicking the controller dispatching is certainly doable. Something to this effect could work (code untested):
if (isset($_GET['action'])) {
new Actions()->dispatch('action_'.$_GET['action']);
}
class Actions {
public function dispatch($action) {
if (method_exists($this, $action)) {
$this->$action($_GET);
} else {
http_response_code(400);
exit(1);
}
}
// The following functions are examples only!
public function action_Create($parameters) {
// Create database record
}
public function action_Read($parameters) {
// Read database record
}
public function action_Update($parameters) {
// Update database record
}
public function action_Delete($parameters) {
// Delete database record
}
}
Then you'd call (for example) action.php?action=Read&name=foo&author=bar

Adding Changes Saved Javascript Popup

This is a MVC3 project using razor. Instead of displaying another view to inform the user that the changes have been saved successfully I would like to simply fire a JavaScript popup informing them... Everything I have found on the web either opens a whole new browser window, or misses what I am trying to accomplish all together... I know there is a simpler way to go about doing this but this is where I am... At the end of the controller function that does the save on the return I simply use redirect and send it to another controller function that displays a screen saying "Changes Have Been Saved Successfully" then the user clicks a button there which will take them back to the index page... IMO this is a bit shotty and think it can be cleaned up through the use of Javascript...I have not found any luck on this yet.. Currently the below code is what I am using:
Function SomeFunctionName()
db.SaveChanges()
Return RedirectToAction(ChangesSaved)
End Function
Function ChangesSaved()
Return View()
End Function
And the javascript that I have implemented in the ChangesSaved view.
#Code
ViewData("Title") = "ChangesSaved"
End Code
<script type="text/javascript">
alert("Changes Have Been Saved Successfully");
</script>
There are a few problems with this though...
How do I tell the javascript When the user clicks OK it should take them to another page.
I did just try the below and since I am very new to java/javascript it failed:
var r=alert("Changes Have Been Saved Successfully");
if (r == true) {
#html.Action("***********","Admin")
}
If I were you I would post your form using Jquery. Then you can set a callback. In Mvc you can return JSON data, a simple value indicating that the save worked would be enough. Then you can call your alert although you might consider using a jQuery UI dialog as it's way more flexible. If you haven't ever used jQuery I wouldn't be afraid, it's easy and there is a lot of great examples out there.
Take a look at this http://api.jquery.com/jQuery.post/ and this, ASP.NET MVC controller actions that return JSON or partial html

ASP.NET MVC. Check if user is authorized from JavaScript

I'm using ASP.NET MVC Framework 3 and Forms Authentication. I know, how to check on servers side, if the user is authorized for some action (with [Authorize]) and I know, how to check this within an action or a view (with User.Identity.IsAuthenticated or other members of 'User').
What I'm trying to do - is to define some JavaScript code, that will be executed differently, depending if the user is authorized.
Consider such script on the page:
<script>
function Foo(){
if(userAuthorized)
alert("You\'re in the system");
} else {
alert("You\'re not authorized");
}
<script>
Function Foo() is triggered by some event, say click. And I'd like to have an ability to check, if user is authorized, on clients side.
The best solution I've came up with is to actually render global variables initialization in view. Like this:
#if(User.Identity.IsAuthenticated)
{
<script>
var userAuthorized = true;
</script>
}
else
{
<script>
var userAuthorized = false;
</script>
}
But it doesn't seems to me as a good approach. Are there any other ways?
Thanks in advance.
PS: This is a usability issue, of course I'm doing necessary checks on server.
I like the idea in #Gaby's comment, though I am not sure whether that's doable since I don't have the whole picture on your project.
At the very least you can simplify your code by doing...
<script>
var userAuthorized = #User.Identity.IsAuthenticated.ToString().ToLower();
</script>
Another couple of options would be to use a custom HTML data- attribute or create a simple ajax request that asks the server if the user is authenticated.

templates vs DOM creation - highly dynamic interface

Building a browsergame I came from PHP to JavaScript, which I now also want to use at the server side.
As I'm going to require Users to have JavaScript either way, I'm going to take extensive use of it. I want to use in in a object-oriented way though.
Considering MVC, Models will be used on both client and server side. Views are only used at the client side.
The interface is split into multiple parts: a main sidemenu, main content and some widgets. I'll take the part I've already done as example:
The menu is split into three categories with multiple entries. Each entry is a link with an attached action (like switching the content).
// menuview:
var self = new View();
var generalMenu = new MenuCategory('generalmenu')
.addEntry(new MenuEntry('overview', new Action()))
.addEntry(new MenuEntry('buildings'))
.addEntry(new MenuEntry('resources'))
// [..more categories..]
self.toData = function() {
return {
id: this.id,
cat: [generalMenu.toData(), infosMenu.toData(), userMenu.toData()]
};
};
At the moment View is a compositum with a toData() method to create data for the template parser(selfmade, simple but supporting iteration). And the actions get attached after creation. I use jQuery as framework:
self.show = function(callback) {
$tpl(this.tpl).parse(this.toData()).lang('main').toHTML(function(html) {
var el = $(html);
el.find('a').click(function (e) {
MenuEntry.actionHandler.execAction(e.target.id);
return false;
});
el.appendTo('#'+self.target);
callback && callback();
});
return this;
};
I have declared an actionhandler to avoid iterating over the links.
I'm not feeling well with this solution, it's not flexible enough. I'd like to treat a view like a real compositum, not with a lot of strange dependencies. Also, I have to reparse the whole View if I change a part. Well, in this example this is not obvious, because the menu wont change while runningtime, but other parts of the interface will.
Now, to finally get to my question: Is there a better solution?
Like having dom references spread over the view, each menuentry having it's own reference and directly attached action? If I'm not using templates anymore, what kind of flexiblity am I losing?
I decided to go without template parser. Each view stores it's node and is able to manipulate it directly if it gets informed to update the data.

Categories