I'd like to hava a Dojo dojox.grid.DataGrid with its data from a servlet.
Problem: The data returned from the servlet does not get displayed, just the message "Sorry, an error has occured".
If I just place the JSON string into the HTML, it works. ARRRRGGH.
Can anyone please help me!
Thanks
Jeff Porter
Servlet code...
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
res.setContentType("json");
PrintWriter pw = new PrintWriter(res.getOutputStream());
if (response != null) pw.println("[{'batchId':'2001','batchRef':'146'}]");
pw.close();
}
HtmL code...
<div id="gridDD" dojoType="dojox.grid.DataGrid"
jsId="gridDD" style="height: 600x; width: 100%;"
store="ddInfo" structure="layoutHtmlTableDDDeltaSets">
</div>
var rawdataDDInfo = ""; // empty at start
ddInfo = new dojo.data.ItemFileWriteStore({
data: {
identifier: 'batchId',
label: 'batchId',
items: rawdataDDInfo
}
});
<script>
function doSelectBatchsAfterDate() {
var xhrArgs = {
url: "../secure/jsonServlet",
handleAs: "json",
preventCache: true,
load: function(data) {
var xx =dojo.toJson(data);
var ddInfoX = new dojo.data.ItemFileWriteStore({data: xx});
dijit.byId('gridDD').setStore(ddInfoX);
},
error: function(error) {
alert("error:" + error);
}
}
//Call the asynchronous xhrGet
var deferred = dojo.xhrGet(xhrArgs);
}
</script>
<img src="go.gif" onclick="doSelectBatchsAfterDate();"/>
When you create the dojo.data.ItemFileWriteStore using the JSON data returned from server. You just provide the items, you still needs to specify the metadata. The correct code should be as below.
var ddInfoX = new dojo.data.ItemFileWriteStore({
data: {
identifier: 'batchId',
label: 'batchId',
items: xx
}
});
And you don't need the dojo.toJson function which converts the JSON object to a JSON string. The dojo.data.ItemFileWriteStore requires a JSON object as the parameter, not a JSON string.
Related
I'm having a hard time getting anything to work with this the way I need it, but I have a working dropzone instance in my Vue project.
I can upload the image and call functions within the dropzone code, however, I need to call a function directly from the form in the html in order to send the 'card' object.
All I need to do is call a function when a file is added through the dropzone form, with the filename.
My code:
<div class="uk-width-3-10">
<form v-on:change="imageChange(card)" method="post" action="{{url('product/parts/upload/store')}}" enctype="multipart/form-data"
class="dropzone" v-bind:id="'dropzone-'+i">
</form>
</div>
...
imageChange(Card){
console.log('working');
},
addCard(){
Vue.nextTick(function () {
new Dropzone("#dropzone-"+cardIndex, {
maxFilesize: 12,
renameFile: function (file) {
var dt = new Date();
var time = dt.getTime();
return time + file.name;
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: true,
timeout: 50000,
removedfile: function (file) {
console.log(file.upload.filename);
var name = file.upload.filename;
var fileRef;
return (fileRef = file.previewElement) != null ?
fileRef.parentNode.removeChild(file.previewElement) : void 0;
},
init: function() {
this.on("addedfile",
function(file) {
instance.imageZoneNames.push({name: file.upload.filename});
console.log(file);
console.log(instance.imageZoneNames);
});
}
});
});
}
Dropzone has many events, You used removedfile() event! there is another event called addedfile() and executes when a file is added to the dropzone list
imageChange(card) {
console.log(card)
},
addCard() {
Vue.nextTick(() => {
new Dropzone('#dropzone-` + cardIndex, {
addedfile(file) {
this.imageChange(file);
}
}
}
}
I have problem with my first MVC project. I'm trying to change values of DropDownList of surnames when select DropDownList of doctor types. I think my action is working. But I cannot use result in view.
Here my codes:
$(function () {
$('select#mCB').change(function () {
var docId = $(this).val();
$.ajax({
dataType: 'json',
data: 'spec=' + docId,
method: 'GET',
url: 'LoadDoctors',
success: function (data) {
$.each(data, function (key, Docs) {
$('select#shCB').append('<option value="0">Select One</option>');
$.each(Docs, function (index, docc) {
$('select#shCB').append(
'<option value="' + docc.Id + '">' + docc.Name + '</option>');
});
});
},
error: function (docID) {
alert(' Error !');
}
});
});
});
Actions:
public static List<Docs> GetDoctorBySpec(string spec)
{
List<Docs> list = new List<Docs>();
string query = "select ID, Familiyasi, Speciality from Doktorlar where Speciality=#spec";
SqlConnection Connection = new SqlConnection(DataBase.ConnectionString);
Connection.Open();
SqlCommand cmd = new SqlCommand(query, Connection);
cmd.Parameters.Add("#spec", spec);
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
list.Add(new Docs
{
Id = dr.GetString(0),
Name = dr.GetString(1)
});
}
return list;
}
enter code here
enter code here
[HttpGet]
public ActionResult LoadDoctors(string spec)
{
List<Docs> list = DoctorsService.GetDoctorBySpec(spec);
if (list == null)
{
return Json(null);
}
return Json(list);
}
And here my DropDownLists:
<div class="editor-label">
#Html.LabelFor(model => model.DoktorTuri)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.DoktorTuri, new SelectList(ViewBag.Vrachlar), new { #id = "mCB", #class = "vrachlar" })
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Shifokori)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Shifokori, Enumerable.Empty<SelectListItem>(), new { #id = "shCB", #class = "vrachlar" })
</div>
Where is my mistake? Thanks for answers
A 500 (Internal Server Error) almost always means that your throwing an exception on the server. Best guess is in your case it's because your method
DoctorsService.GetDoctorBySpec(spec);
does not accept null as a parameter and the value of spec is null because your never pass it value to the controller. As stann1 has noted your ajax option needs to be
data: {spec: docId},
In addition, you do not specify the JsonRequestBehavior.AllowGet parameter which means the method will fail.
All of this can be easily determined by debugging your code, both on the server and by using your browser tools (in particular the Network tab to see what is being sent and received along with error messages)
However this is only one of many problems with your code.
Firstly, unless Docs contains only 2 properties (the values you need for the option's value attribute and display text), your unnecessarily wasting bandwidth and degrading performance by sending a whole lot of data to the client which is never used. Instead, send a collection of anonymous objects
[HttpGet]
public ActionResult LoadDoctors(string spec)
{
List<Docs> list = DoctorsService.GetDoctorBySpec(spec);
if (list == null)
{
return Json(null, JsonRequestBehavior.AllowGet);
}
var data = list.Select(d => new
{
Value = d.Id,
Text = d.Name
});
return Json(data, JsonRequestBehavior.AllowGet);
}
Next, your script will only ever generate multiple <option value="0">Select One</option> elements (one for each item in the collection) because data in $.each(data, function (key, Docs) { is your collection, and Docs is the item in the collection. Your second $.each() function will never produce anything because Docs is not a collection.
You script should be (note I have use the short version $.getJSON() rather than the longer $.ajax() and also used the default id attributes generated by the html helpers - its not clear why you would want to change the id's using new { id = "mCB" }?)
var url = '#Url.Action("LoadDoctors")'; // never hard code your url's
var shifokori = $('#Shifokori'); // cache it
$('#DoktorTuri').change(function () {
$.getJSON(url, { spec: $(this).val() }, function(data) {
if (!data) { // only necessary depending on the version of jquery
// oops
}
// clear existing options and append empty option with NULL value (not zero)
// so validation will work
shifokori.empty().append($('<option></option>').val('').text('Select One'));
$.each(data, function (index, doc) {
shifokori.append($('<option></option>').val(doc.Value).text(doc.Text));
});
}).fail(function (result) {
// oops
});
});
The data param of the call needs to be a Javascript object literal:
$.ajax({
dataType: 'json',
data: {spec: docId},
method: 'GET',
....
});
Also, try to debug your controller and use a rest extension (or Fiddler) to test the payload, you would catch such error easily yourself ;)
A contrived example of bi-directional data binding
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
m.render("body", [
m("input", {onchange: m.withAttr("value", controller.user.name), value: controller.user.name()})
]);
}
};
https://lhorie.github.io/mithril/mithril.withAttr.html
I tried the above code does not work nothing.
It was the first to try to append the following.
m.mount(document.body, user);
Uncaught SyntaxError: Unexpected token n
Then I tried to append the following.
var users = m.prop([]);
var error = m.prop("");
m.request({method: "GET", url: "/users/index.php"})
.then(users, error);
▼/users/index.php
<?php
echo '[{name: "John"}, {name: "Mary"}]';
Uncaught SyntaxError: Unexpected token n
How do I operate the m.withAttr tutorials code?
Try returning m('body', [...]) from your controller.
view: function (ctrl) {
return m("body", [
...
]);
}
render should not be used inside of Mithril components (render is only used to mount Mithril components on existing DOM nodes).
The example is difficult to operate because it's contrived, it's not meant to be working out-of-the-box. Here's a slightly modified, working version:
http://jsfiddle.net/ciscoheat/8dwenn02/2/
var user = {
model: function(name) {
this.name = m.prop(name);
},
controller: function() {
return {user: new user.model("John Doe")};
},
view: function(controller) {
return [
m("input", {
oninput: m.withAttr("value", controller.user.name),
value: controller.user.name()
}),
m("h1", controller.user.name())
];
}
};
m.mount(document.body, user);
Changes made:
m.mount injects html inside the element specified as first parameter, so rendering a body element in view will make a body inside a body.
Changed the input field event to oninput for instant feedback, and added a h1 to display the model, so you can see it changing when the input field changes.
Using m.request
Another example how to make an ajax request that displays the retrieved data, as per your modifications:
http://jsfiddle.net/ciscoheat/3senfh9c/
var userList = {
controller: function() {
var users = m.prop([]);
var error = m.prop("");
m.request({
method: "GET",
url: "http://jsonplaceholder.typicode.com/users",
}).then(users, error);
return { users: users, error: error };
},
view: function(controller) {
return [
controller.users().map(function(u) {
return m("div", u.name)
}),
controller.error() ? m(".error", {style: "color:red"}, "Error: " + controller.error()) : null
];
}
};
m.mount(document.body, userList);
The Unexpected token n error can happen if the requested url doesn't return valid JSON, so you need to fix the JSON data in /users/index.php to make it work with your own code. There are no quotes around the name field.
I have four controls on the page, a simple form with first and last names, date of birth and this drop down that contains some names of countries. When I make changes to the these controls I am able to see those changes in my viewModel that is passed in as a parameter in the SavePersonDetails POST below, but I never see the LocationId updated in that view model and I am not sure why.
This is what I have in my markup, Index.cshtml:
#model Mvc4withKnockoutJsWalkThrough.ViewModel.PersonViewModel
#using System.Globalization
#using Mvc4withKnockoutJsWalkThrough.Helper
#section styles{
#Styles.Render("~/Content/themes/base/css")
<link href="~/Content/Person.css" rel="stylesheet" />
}
#section scripts{
#Scripts.Render("~/bundles/jqueryui")
<script src="~/Scripts/knockout-2.1.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script src="~/Scripts/Application/Person.js"></script>
<script type="text/javascript">
Person.SaveUrl = '#Url.Action("SavePersonDetails", "Person")';
Person.ViewModel = ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)));
var userObject = '#Html.Raw(Json.Encode(Model))';
var locationsArray = '#Html.Raw(Json.Encode(Model.Locations))';
var vm = {
user : ko.observable(userObject),
availableLocations: ko.observableArray(locationsArray)
};
ko.applyBindings(vm);
</script>
}
<form>
<p data-bind="with: user">
Your country:
<select data-bind="options: $root.availableLocations, optionsText: 'Text', optionsValue: 'Value', value: LocationID, optionsCaption: 'Choose...'">
</select>
</p>
</form>
This is my View Model:
public class PersonViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
public string LocationId { get; set; }
public IEnumerable<SelectListItem> Locations { get; set; }
}
I have a simple controller that loads my Person and a drop down list containing three countries.
private PersonViewModel _viewModel;
public ActionResult Index()
{
var locations = new[]
{
new SelectListItem { Value = "US", Text = "United States" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "MX", Text = "Mexico" },
};
_viewModel = new PersonViewModel
{
Id = 1,
FirstName = "Test",
LastName = "Person",
DateOfBirth = new DateTime(2000, 11, 12),
LocationId = "", // I want this value to get SET when the user changes their selection in the page
Locations = locations
};
_viewModel.Locations = locations;
return View(_viewModel);
}
[HttpPost]
public JsonResult SavePersonDetails(PersonViewModel viewModel)
{
int id = -1;
SqlConnection myConnection = new SqlConnection("server=myMachine;Trusted_Connection=yes;database=test;connection timeout=30");
try
{
// omitted
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
myConnection.Close();
}
return Json(id, "json");
}
Lastly, here is my Person.js file, I am using knockout
var Person = {
PrepareKo: function () {
ko.bindingHandlers.date = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
element.onchange = function () {
var observable = valueAccessor();
observable(new Date(element.value));
}
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var observable = valueAccessor();
var valueUnwrapped = ko.utils.unwrapObservable(observable);
if ((typeof valueUnwrapped == 'string' || valueUnwrapped instanceof String) && valueUnwrapped.indexOf('/Date') === 0) {
var parsedDate = Person.ParseJsonDate(valueUnwrapped);
element.value = parsedDate.getMonth() + 1 + "/" + parsedDate.getDate() + "/" + parsedDate.getFullYear();
observable(parsedDate);
}
}
};
},
ParseJsonDate: function (jsonDate) {
return new Date(parseInt(jsonDate.substr(6)));
},
BindUIwithViewModel: function (viewModel) {
ko.applyBindings(viewModel);
},
EvaluateJqueryUI: function () {
$('.dateInput').datepicker();
},
RegisterUIEventHandlers: function () {
$('#Save').click(function (e) {
// Check whether the form is valid. Note: Remove this check, if you are not using HTML5
if (document.forms[0].checkValidity()) {
e.preventDefault();
$.ajax({
type: "POST",
url: Person.SaveUrl,
data: ko.toJSON(Person.ViewModel),
contentType: 'application/json',
async: true,
beforeSend: function () {
// Display loading image
},
success: function (result) {
// Handle the response here.
if (result > 0) {
alert("Saved");
} else {
alert("There was an issue");
}
},
complete: function () {
// Hide loading image.
},
error: function (jqXHR, textStatus, errorThrown) {
// Handle error.
}
});
}
});
},
};
$(document).ready(function () {
Person.PrepareKo();
Person.BindUIwithViewModel(Person.ViewModel);
Person.EvaluateJqueryUI();
Person.RegisterUIEventHandlers();
});
As you can see, I have the data in the page but none of them show as selected
Your solution is overly complex and is leading to certain weirdness with your data. Instead of trying to patch the Titanic, your best bet is to start over and simplify:
Your page's model contains all the information you need. There's no need to try to create two totally separate view models to work with the user data versus locations. With the mapping plugin, you can specify different "view models" for various objects in your main view model, and there's a simpler pattern that can be followed to set all that up. Here's what I would do:
// The following goes in external JS file
var PersonEditor = function () {
var _init = function (person) {
var viewModel = PersonEditor.PersonViewModel(person);
ko.applyBindings(viewModel);
_wireEvents(viewModel);
}
var _wireEvents = function (viewModel) {
// event handlers here
}
return {
Init: _init
}
}();
PersonEditor.PersonViewModel = function (person) {
var mapping = {
'Locations': {
create: function (options) {
return new PersonEditor.LocationViewModel(options.data)
}
}
}
var model = ko.mapping.fromJS(person, mapping);
// additional person logic and observables
return model;
}
PersonEditor.LocationViewModel = function (location) {
var model = ko.mapping.fromJS(location);
// additional location logic and observables
return model;
}
// the following is all you put on the page
<script src="/path/to/person-editor.js"></script>
<script>
$(document).ready(function () {
var person = #Html.Raw(#Json.Encode(Model))
PersonEditor.Init(person);
});
</script>
Then all you need to bind the select list to the locations array is:
<p>
Your country:
<select data-bind="options: Locations, optionsText: 'Text', optionsValue: 'Value', value: LocationId, optionsCaption: 'Choose...'">
</select>
</p>
Based on your updated question, do this.
1.We do not need locationsArray actually. Its already in user.Locations (silly me)
2.On Index.cshtml, page change the JavaScript like this.
var userObject = #Html.Raw(Json.Encode(Model)); // no need for the quotes here
jQuery(document).ready(function ($) {
Person.PrepareKo();
Person.EvaluateJqueryUI();
Person.RegisterUIEventHandlers();
Person.SaveUrl = "#Url.Action("SavePersonDetails", "Knockout")";
Person.ViewModel = {
user : ko.observable(userObject)
};
Person.BindUIwithViewModel(Person.ViewModel);
});
3.On your Person.js page, inside RegisterUIEventHandlers #Save button click event, do this.
$('#Save').click(function (e) {
var updatedUser = Person.ViewModel.user();
updatedUser.Locations.length = 0; // not mandatory, but we don't need to send extra payload back to server.
// Check whether the form is valid. Note: Remove this check, if you are not using HTML5
if (document.forms[0].checkValidity()) {
e.preventDefault();
$.ajax({
type: "POST",
url: Person.SaveUrl,
data: ko.toJSON(updatedUser), // Data Transfer Object
contentType: 'application/json',
beforeSend: function () {
// Display loading image
}
}).done(function(result) {
// Handle the response here.
if (result > 0) {
alert("Saved");
} else {
alert("There was an issue");
}
}).fail(function(jqXHR, textStatus, errorThrown) {
// Handle error.
}).always(function() {
// Hide loading image.
});
}
});
5.Finally, our markup
<p data-bind="with: user">
Your country:
<select data-bind="options: Locations,
optionsText: 'Text',
optionsValue: 'Value',
value: LocationId,
optionsCaption: 'Choose...'">
</select>
</p>
On an unrelated side-note,
The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are
deprecated as of jQuery 1.8. To prepare your code for their eventual
removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
I have a function in which I am doing a dojo.xhrPost(). Now the returning data is wrapped in an unwanted <div> which is framework specific and cannot be removed. How can I strip away the div element. Here is my code.
function sendForm() {
var resultNode = dojo.create("li");
dojo.xhrPost({
url: "${sectionaddurl}",
form: dojo.byId("sectionform"),
load: function(newContent) {
dojo.style(resultNode,"display","block");
resultNode.innerHTML = newContent;
},
error: function() {
resultNode.innerHTML = "Your form could not be sent.";
}
});
$("#sectionform")[0].reset();
dojo.place(resultNode, "existing_coursesection", "first");
}
In jquery we would do $("#some_ID").text(); where the id will be the div obtained via ajax.
Will dojo allow me to manipulate the request data which is like <div id="unwanted_div">containing my text</div>
any ideas?
I am not sure these are the "best" ways to go at it but they shoud work
1) Have the data be interpreted as XML instead of plain text:
dojo.require('dojox.xml.parser');
dojo.xhrPost({
//...
handleAs: 'xml',
//...
load: function(response_div){
//content should be xml now
result.innerHTML = dojox.xml.parser.textContent(response_div);
}
//...
})
2) Convert it to html and then process it
//create a thworwaway div with the respnse
var d = dojo.create('div', {innerHTML: response});
result.innerHTML = d.firstChild.innerHTML;
2.1) Use dojo.query instead of .firstChild if you need smore sofistication.
I prefer handle as JSON format :) , dojo have more utilities to access and to iterate the response.
dojo.xhrGet({
url : url,
handleAs : "json",
failOk : true, //Indicates whether a request should be allowed to fail
//(and therefore no console error message in the event of a failure)
timeout : 20000,
content: {//params},
load: function(){ // something },
preventCache: true,
error: function(error, ioargs) {
console.info("error function", ioargs);
var message = "";
console.info(ioargs.xhr.status, error);
//error process
},
handle: function(response, ioargs) {
var message = "";
console.info(ioargs.xhr.status, error);
switch (ioargs.xhr.status) {
case 200:
message = "Good request.";
break;
case 404:
message = "The page you requested was not found.";
break;
case 0:
message = "A network error occurred. Check that you are connected to the internet.";
break;
default:
message = "An unknown error occurred";
}
}
});