Handling Form Post in asp.net MVC when dojo grid is present - asp.net-mvc-4

I am pretty new to web based applications development.I am using ASP.Net MVC4 with dojo toolkit. My requirement is like I have certain textboxes to capture data and also one dojo grid to capture certain details which are in a tabular format. So I am using Dojo grid(http://dojotoolkit.org/api/1.8/dojox/grid/DataGrid) with ItemFileWriteStore. My view is like below(I am using razor)
#using (Html.BeginForm("CreateNewData", "Home", FormMethod.Post, new { id = "myForm" }))
{
<div class="controlWrapper">
<div class="controlLabel">
#Html.DisplayNameFor(model => model.Name)
</div>
<div class="controlValue">
#Html.TextBoxFor(model => model.Name)
</div>
</div>
<div class="controlWrapper">
<h4>
Table Items</h4>
<div id="myGrid">
</div>
<div id="addRemoveMode">
<button data-dojo-type="dijit.form.Button" id="addButton" onclick="addRecord()">
Add</button>
<button data-dojo-type="dijit.form.Button" id="removeButton" onclick="removeRecord()">
Remove Selected Rows
</button>
</div>
</div>
}
My java script to create grid is like below
require(["dojo/ready",
"dojox/grid/DataGrid",
"dojo/data/ItemFileWriteStore",
"dojo/json",
"dojo/query",
"dijit/form/TextBox"
], function (ready, DataGrid, ItemFileWriteStore, Json, query, TextBox) {
ready(function () {
var layout = [[
{ name: 'ID', field: 'ID', hidden: true },
{ name: 'Label', field: 'Label', width: '10%', editable: true },
{ name: 'Position', field: 'Position', width: '10%', editable: true }
]];
var attCodeData = {
identifier: 'ID',
items: []
};
console.log(globalVar);
attCodeData["items"] = globalVar;
myStore= new ItemFileWriteStore({ data: attCodeData })
myGrid= new DataGrid({
store: myStore,
structure: layout,
rowSelector: '20px'
},"divGrid");
myGrid.startup();
}
My problem is since the grid is inside the form, whenever I add or remove a row, page is getting submitted to Post method mentioned in form. I just need to post the whole data so that I can process together. So I moved my grid outside Form. Now I am confused how to capture the whole data(data in text boxes and grid together) and submit to a controller method. Please help me.

To preventing whole page from getting submitted to Post method, you should use ajax solutions for sending and receiving data.
Take a look at this :DataGrid View with "CRUD operations" using Dojo DataGrid, JsonRest Store, Entity Framework, SQL Server, ASP.NET MVC Web API
and this: Ajax with dojo/request. I hope, they help.

Related

Data attribute bound to external variable not reactive to variable changes

I'm beginning to incorporate Vue.js (v2.5.17) for a few small things on an ecommerce website, but I'm new to Vue and having some troubles. Due to some Laravel blade structure that I don't have the option of refactoring at this time, I have to split the various parts of this functionality into distinct components, and I'm having trouble with the data in one Vue instance reacting to events on the other.
Here's a CodePen with a stripped down version of the issue: https://codepen.io/jgabrielsen/pen/bxRroM/
For easy reference, the JS:
var cartStore = {
state: {
products: [PRODUCT ARRAY],
active: false
},
}
var cartHeader = new Vue({
el: '#cartHeader',
data: {
products: cartStore.state.products,
},
methods: {
setActiveTrue: function() {
cartStore.state.active = true;
console.log('Show Cart');
},
setActiveFalse:function() {
cartStore.state.active = false;
console.log('Hide Cart');
},
},
})
var cartPreview = new Vue({
el: '#cartPreview',
data: {
products: cartStore.state.products,
active: cartStore.state.active,
},
methods: {
total: function() {
var sum = 0;
for (var i = 0; i < this.products.length; i++) {
sum += this.products[i][1]
}
return sum
},
},
})
And the HTML
<div class="header">
<a id="cartHeader" #mouseover="setActiveTrue" #mouseout="setActiveFalse">CART({{ this.products.length }})</a>
</div>
<div id="cartPreview" v-show="active">
<ul>
<li v-for="product in products">
<div class="col-80">
{{ product[0] }}
</div>
<div class="col-20" style="text-align:right;">
${{ product[1] }}
</div>
</li>
</ul>
<div class="row">
<div class="col-100" style="text-align:right;">
Total Products: {{ this.products.length }}<br>
Total: ${{ this.total() }}
</div>
</div>
</div>
Long story short, I need the cartPreview instance to show up when cartHeader instance is hovered over (a basic popover effect).
Here's how I'm currently trying to do this:
I have a var cartStore that contains an array of all the cart preview data, as well as an active state.
cartPreview has a data attribute active bound to cartStore.state.active (which is false by default) and v-show="active", so it's hidden until something sets it's data attribute active to true.
cartHeader has #mouseover="setActiveTrue" and #mouseout="setActiveFalse", to toggle cartPreview's active attribute by way of the bound state in cartStore.
I can tell that the mouseover and mouseout events are firing because cartStore.state.active does change to true and false correctly and the console logs fire, but the corresponding data attribute in the cartPreview is not reactive to these changes.
I feel like I must be overlooking something super simple and/or making some major noob mistakes, but after poring over my code dozens of times and searching high and low, I'm stumped as to why it's not reactive.
I finally figured out a solution.
cartStore.state.products was reactive between cartHeader and cartPreview for adding and removing the products (methods I removed from my example because I didn't think they were relevant), but cartStore.state.active wasn't. The only difference I could see was that the cart data in products was stored in an array and active wasn't, so I made cartStore.state.active an array:
var cartStore = {
state: {
products: [PRODUCT ARRAY],
active: [ false ]
},
}
...updated it with splice:
methods: {
setActiveTrue: function() {
this.active.splice(0,1,true);
},
setActiveFalse:function() {
this.active.splice(0,1,false);
},
},
...and added v-show="active[0]" to the component, and lo and behold, it works.

Adding radio buttons to Laravel Spark - Vue component page

I tried to stay away from the Vue components of Spark as much as possible but I discovered I had to implement a certain mail settings so I can't hold it much longer.
Luckily the Spark documentation contains a small cookbook for adding profile fields:
https://spark.laravel.com/docs/4.0/adding-profile-fields
Most parts are within my (limited PHP) comfort zone:
First the blade php:
Mail settings
<div class="col-md-6">
<label class="radio-inline"><input type="radio" value="profile" v-model="form.type" name="profile">Profile</label>
<label class="radio-inline"><input type="radio" value="website" v-model="form.type" name="website">Website</label>
<label class="radio-inline"><input type="radio" value="combined" v-model="form.type" name="combined">Combined</label>
<span class="help-block" v-show="form.errors.has('mail-settings')">
#{{ form.errors.get('mail-settings') }}
</span>
</div>
</div>
Which is integrated:
<!-- Update Mail settings -->
#include('settings.profile.update-mail-settings')
So as can be seen in the previous code block, I wish to store the result of 3 radio buttons.
However the linked Vue js file is giving my headaches:
Vue.component('update-mail-settings', {
props: ['user'],
data() {
return {
form: new SparkForm({
profile: ''
website: ''
combined: ''
})
};
},
mounted() {
this.form.mailsettings = this.user.mailsettings;
},
methods: {
update() {
Spark.put('/settings/profile/mail-settings', this.form)
.then(response => {
Bus.$emit('updateUser');
});
}
}
});
But how on earth do I integrate the radio buttons in the SparkForm?
In Vue, data binding occurs when you v-model to the object by name. Or in other words, you call v-model="object.property" on an input. When the user fills out the form, the value of form.type will match the form input. So simply change your form object to read:
data() {
return {
form: new SparkForm({
type: '' <- this can now be v-modeled to "form.type"
})
};
},
Your radio buttons don't need to change because they are bound correctly: v-model="form.type"
https://v2.vuejs.org/v2/guide/forms.html#Radio

Event driven binding / rebinding of v-model / v-bind?

I'm really struggling on how to implement a pattern inline with the "Vue philosophy".
Imagine a list of items that you'd like to edit. There are numerous examples of how to edit those items "inline". But I'd like to edit my items through the same, persistent form. So when you click a list item, the form input "rebinds" to clicked list item.
Here's a working example: http://jsbin.com/sopakid/3/edit?html,js,output which uses a method (updateRecord) to copy the form input (bound to editRecord), to the referenced li's data binding (messages[index]).
data: {
messages: [
{ name: "Dale Cooper", message: "Black as midnight on a moonless night" },
{ name: "Shelly Johnson", message: "I've got one man too many in my life and I'm married to him." },
{ name: "Sheriff Truman", message: "Jelly donuts?"}
],
editRecord:
{ name: "", message: "" }
},
updateRecord: function(){
var index = this.editRecord.index;
this.messages[index].name = this.editRecord.name;
this.messages[index].message = this.editRecord.message;
}
Looking for any insight as to how to better implement this pattern. Thanks!
Idiomatically, you don't really need any methods in this case. You can set the editRecord directly in the template. Additionally, if you set the editRecord to the selected message, then you don't even need an update button or a need to keep track of the index.
var app = new Vue({
el: '#app',
data: {
editRecord:{ name: null, message: null },
messages: [
{ name: "Dale Cooper", message: "Black as midnight on a moonless night" },
{ name: "Shelly Johnson", message: "I've got one man too many in my life and I'm married to him." },
{ name: "Sheriff Truman", message: "Jelly donuts?"}
]
}
});
These are the changes I made to your template
<div id="app">
<div class="messages">
<ul>
<li class="message" v-for="(message, index) in messages" #click="editRecord = message">
<div class="message__name">
{{message.name}}
</div>
<div class="message__body">
{{message.message}}
</div>
</li>
</ul>
</div>
<div class="edit-form" v-if="editRecord">
<label for="name">Name</label>
<input name="name" type="text" placeholder="Name" v-model="editRecord.name">
<label for="message">Message</label>
<textarea name="message" id="" cols="30" rows="6" v-model="editRecord.message"></textarea>
</div>
</div>
Here is your fiddle updated.
The result takes advantage of Vue's reactivity and as you edit in your form you can see the changes taking place in the list as well.
Some people may like the approach you've taken though, where the edits they make are not complete until they specify they are. A lot of this is a matter of taste.
I would warn against using index to track your selected record, however. If the list changes underneath you, the indexes change. Use an id property on your messages. If you go with the reactive approach though, you don't really need that.

DataGrid Dojo Not Working in Widget

I have a widget on dojo, but it does not display the datagrid. If I make the example outside the widget works. I see the code by firebug, you can not mistake, however, I can see the div inspect and there is nothing inside. The Builder runs, but does not load the grid in div.
Widget.js
define([ "dojo/_base/declare",
"dojo/text!./FormularioQCI.html",
"icm/base/_BaseWidget",
"dojo/store/JsonRest",
"dojo/store/Memory",
"dojo/store/Cache",
"dojox/grid/DataGrid",
"dojo/data/ObjectStore"
],
function(declare, template, _BaseWidget, JsonRest, Memory, Cache, DataGrid, ObjectStore){
return declare("icm.custom.pgwidget.formularioQCI.FormularioQCIWidget", [_BaseWidget], {
templateString: template,
widgetsInTemplate: true,
constructor: function(){
alert("X");
myStore = dojo.store.Cache(dojo.store.JsonRest({target:"rest/formularioQCI/get"}), dojo.store.Memory());
grid = new dojox.grid.DataGrid({
store: dataStore = dojo.data.ObjectStore({objectStore: myStore}),
structure: [
{name:"State Name", field:"name", width: "200px"},
{name:"Abbreviation", field:"abbreviation", width: "200px", editable: true}
]
}, "target-node-id"); // make sure you have a target HTML element with this id
grid.startup();
alert("Y");
dojo.query("#save").onclick(function(){
alert("X");
dataStore.save();
});
var id = 0;
dojo.query("#add").onclick(function(){
dataStore.newItem({
name: "col2-" + id,
abbreviation: "col3-" + id
});
id++;
});
},
/**
* #private destroys this widget
*/
destroy: function() {
//Do any custom clean up here
this.inherited(arguments);
}
});});
Widget.html
<div style="width: 100%; height: 100%;">
<div id="target-node-id">
</div>
<button id="save">Save
</button>
<button id="add">Add Linha
</button>
</div>
you need to write you code in the postCreate function.
Simplest way would be to replace the constructor keyword with postCreate.
The reason being that the "target-node-id" will not be available until the postCreate function call.
postCreate: function(){
this.inherited(arguments);
// Rest of your code here.
alert("X");
...
}

WinJS flipview control and item template

trying to use the FlipView control in WinJS and having some issues. I am able to bind it to a datasource and get the URL/picture property show up in the flipview control content pane but it fails to load the picture - any suggestions :(
I have made sure that src property of the image tags points to the URL/picture property. I am able to load the image via a normal img tag.
listed below is the template definition and data source - as always, appreciate any pointers :)
datasource:
var dataArray = [
{ type: "item", title: "Hole 1", picture: "/images/IMG_0550.jpg" },
{ type: "item", title: "Hole 2", picture: "/images/IMG_0564.jpg" },
{ type: "item", title: "Hole 3", picture: "/images/IMG_0572.jpg" },
{ type: "item", title: "Hole 4", picture: "/images/IMG_0594.jpg" },
{ type: "item", title: "Hole 5", picture: "/images/IMG_0605.jpg" }
];
var dataList = new WinJS.Binding.List(dataArray);
// Create a namespace to make the data publicly
// accessible.
WinJS.Namespace.define("ImageData", {
bindingList: dataList,
array: dataArray
});
flipview binding:
Gallery content goes here.
<div id="simple_ItemTemplate" data-win-control="WinJS.Binding.Template">
<div>
<img src="#" data-win-bind="src: picture; alt: title" />
<div>
<h2 data-win-bind="innerText: title"></h2>
</div>
</div>
</div>
<div id="basicFlipView"
data-win-control="WinJS.UI.FlipView"
data-win-options="{ itemDataSource : ImageData.bindingList.dataSource, itemTemplate : simple_ItemTemplate }">
</div>
</section>
use itemTemplate : select('#simple_ItemTemplate') instead of `itemTemplate : simple_ItemTemplate'
It is good to set template and datasource in code to avoid typo error and code can be debugged also.
basicFlipView.winControl.itemTemplate = simple_ItemTemplate;
basicFlipView.winControl.itemDataSource = dataList;
I do not agree with ankur comment, from my POV, databinding and MVVM is the way to go.
About your question, run the project and use DOM explorer to see what get generated, also use a class instead of an id as template identifier (since it gets generated multiple times)