Kendo UI MVVM Datasource binding to html input element - mvvm

newbie to kendo
The kendo datasource only returns arrays and my RESTful api returns a client as an array of one element.
However, I cannot seem to bind the 'Name' field of the client to an html input box.
I can however consume the data if I put it in a 'ul', as shown in the below code. I know the json response is well formed because I can console.log(obj[0].Name);
I attempted to return obj[0] in the data: of the datasource but that just broke everything. (no slice error message, as it tries to slice up the array).
I'm sure this is easy but I must be just thinking about this all wrong...
Html and js below:
<div data-role="view" data-title="Client Detail" data-model="app.clientView">
<!-- this does not work -->
<input data-bind="value: app.clientView.data"/>
<input data-bind="value: app.clientView.data[0].Name"/>
<input data-bind="value: app.clientView.data.Name"/>
<!-- this works -->
<ul data-role="listview" data-source="app.clientView.data" data-template="client-template"></ul>
<script type="text/x-kendo-template" id="client-template">
<a href="components/clientView/view.html?id=#: ID #">
<div>#: Name #</div>
<div>#: LastActivityOn #</div>
</a>
</script>
app.clientView = kendo.observable({
data: new kendo.data.DataSource({
transport: {
read: {
url: app.uri + "clients/69", //+ id,
type: "get",
dataType: "json",
beforeSend: function (req) {
req.setRequestHeader('X-authKey', app.key);
}
}
},
schema: {
data: function (response) {
console.log(response);
var obj = $.parseJSON(response);
console.log(obj[0].Name);
return obj;
}
}
})
});

Kendo UI MVVM value bindings cannot point to a Kendo UI DataSource instance. Only source bindings can do that.
In your case, rework your implementation and add some new fields to the viewModel (app.clientView), which can be used for value bindings. It is OK to populate these fields after the DataSource instance receives its data.
On a side note, there is no need to specify viewModel fields verbosely by including the viewModel reference in the bindings configuration. You only need the field names there. Check the Kendo UI MVVM demos.

Related

Vue: Collect all (or some) form values simultaneously

I'm trying to understand if I can achieve with vue.js the same handy process I use to follow with vanilla/jquery to collect simultaneously all (or only some of) the form fields I need.
When dealing with forms usually I never submit them the old school way, instead, I add a class my-update to the form fields I want to send and then I loop them this way:
let objectToUpdate = {};
$(".my-update").each(function(index, element) {
objectToUpdate[$(this).data("db-field")] = $(this).val();
});
Then I just pass the object to an Ajax POST call and send it to the backend API.
With Vue, it's way simple to get data since we have the property (usually called data) already available within the Vue instance but the problem is if I just send the this.$data it will catch not only the properties (all of them without choice) but also all methods included in the object (getter/setter, ...).
Do you have any best practice or suggestions to share to achieve the same I usually do with a couple of lines of jquery but in Vue?
Usually in Vue form controls are binded to data via v-model. Let's say my Vue instance/component is like:
new Vue({
data: {
user: {
name: '',
surname: '',
phone: '',
}
},
methods: {
send() {
// send this.user through http
}
}
});
And my template is like:
<form #submit="send">
<input name="username" v-model="user.name" />
<input name="surname" v-model="user.surname" />
<input name="phone" v-model="user.phone" />
<button> send </button>
</form>
In such scenario, you have all the user information in your component/instance via this.user. You don't need to send this.$data at all if you create an object to manage your form fields (like this.user in this example).

How do I use the autoform update form with flowrouter in Meteor?

I'm using flowrouter in my Meteor project, and I'm trying to figure out how to use it with autoform update. In other words, I'm trying to create a form to update my entity. This means that somehow the object needs to be passed to the template, but I'm not exactly sure how According to the autoform docs you should do something like this;
<template name="updateBookForm">
{{> quickForm collection="Books" doc=this id="updateBookForm" type="update"}}
</template>
but this example pertains to iron router. What additional code do I need to make the autoform update work with flow router ?
update ...
I tried the following
Template.UpdateItem.helpers({
item: function () {
var theItem = Items.findOne({_id: FlowRouter.current().params.itemId});
console.log("the item:"+JSON.stringify(theItem));
return theItem
}
});
and in my template
{{#with item}}
<div>
{{> autoForm collection="Items" id="updateItemForm" doc=item class= "new-item-form" type="update"}}
</div>
{{/with}}
but I'm still getting mothing ...
it doesn't know what "this" is; it needs to be a chunk of JSON from your db. typically, i wrap the autoforms like this:
{{#with getDocument}}
{{> quickForm collection="Books" doc=this id="updateBookForm" type="update"}}
{{/with}}
... and define a corresponding helper in the JS:
getDocument() {
return Books.findOne({isbn: '978-3-16-148410-0'});
}
i am using flow router, this isn't an iron-router specific use case.

Grails forms & URL mapping

I am writing a Grails app where I would like to setup a form that allows a user to type in an image ID number and this value will be passed to a controller / action that retrieves the image from S3 for the given image ID.
The desired url would be of the format example.com/results/1234. I have setup the following URL mappings:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/results/$id?" {
controller = "s3Image"
action = "getS3Image"
}
"/"(view:"/index")
"500"(view:'/error')
}
}
The following is how I have setup a form:
<g:form controller="results" method="get">
<input type="text" name="id" class="input-xxlarge" placeholder="http://www.example.com">
<button class="btn btn-inverse">Submit</button>
</g:form>
However this seems to submit the form to example.com/results?id=12345.
How would I alter my form or mappings such that I can produce the desired url after form submission?
Thanks!
<g:form controller="results" method="get">
will generate an HTML form whose action URL is /results (the reverse URL mapping for a controller named "results" with no action or id). When this form is submitted, the browser will add ?id=1234 to the end of this URL because the form method is GET. This is not something you can influence in your URL mappings on the server side.
Instead, you should have your form POST to a different controller action that redirects to the getS3Image action. The redirect will have access to the ID on the server side, so can generate the friendly-looking URL for the redirect.
UrlMappings:
"/results/$id?" {
controller = "s3Image"
action = "getS3Image"
}
"/findImage" {
controller = "s3Image"
action = "find"
}
S3ImageController:
def find() {
redirect(action:"getS3Image", id:params.id)
}
def getS3Image() {
// as before
}
GSP:
<g:form controller="s3Image" action="find" method="post">
<input type="text" name="id" class="input-xxlarge" placeholder="http://www.example.com">
<button class="btn btn-inverse">Submit</button>
</g:form>
Derek,
what you are seeing is correct behaviour. For the GET request you have two things
URL of request
Parameters
Parameters are appended after urls using urlencode and separated by &, so, when you have form with URL http://mydomain.com/controller/action/, and in this form you have two fields: id, name, then, upon submission, they will be passed like this: http://mydomain.com/controller/action/?id=3&name=someName
URLMappings are mapping only URL part of it. So, in your example UrlMapping are matched only to /results/ and id is not passed.
But that is ok, since you can still access the id parameter in your controller, just do it like this (inside s3Image controller):
def getS3Image() {
def id = params.id
}
Try very simple change in UrlMapping:
"/results/$id?" {
controller = "s3Image"
action = "getS3Image"
id = $id
}
and then for sure you have the id accessible in the s3Image controller via:
def id = params.id
I think you have two problems here. First, UrlMappings rules are matched in order of appearance, from top to bottom. First rule that grails matches is "/$controller/$action?/$id?". Move your rule "/results/$id?" above and it should take precedence. - check comment below post.
Your second mistake is declaration of form. I think you've meant:
<g:form controller="s3Image" method="getS3Image">

ASP .NET MVC 2 - How do I pass an object from View to Controller w/ Ajax?

I have an object MainObject with a list of objects, SubObjects, among other things. I am trying to have the user click a link on the View to add a new SubObject to the page. However, I am unable to pass the MainObject I am working with into the Action method. The MainObject I currently receive is empty, with all its values set to null. How do I send my controller action the MainObject that was used to render the View originally?
The relevant section of the view looks like this:
<div class="editor-list" id="subObjectsList">
<%: Html.EditorFor(model => model.SubObjects, "~/Views/MainObject/EditorTemplates/SubObjectsList.ascx")%>
</div>
<%: Ajax.ActionLink("Add Ajax subObject", "AddBlanksubObjectToSubObjectsList", new AjaxOptions { UpdateTargetId = "subObjectsList", InsertionMode = InsertionMode.Replace })%>
The relevant function from the controller looks like this:
public ActionResult AddBlanksubObjectToSubObjectsList(MainObject mainobject)
{
mainobject.SubObjects.Add(new SubObject());
return PartialView("~/Views/MainObject/EditorTemplates/SubObjectsList.acsx", mainobject.SubObjects);
}
I ended up with the following:
View:
<div class="editor-list" id="subObjectsList">
<%: Html.EditorFor(model => model.SubObjects, "~/Views/MainObject/EditorTemplates/SubObjectsList.ascx")%>
</div>
<input type="button" name="addSubObject" value="Add New SubObject" onclick="AddNewSubObject('#SubObjectList')" />
Control:
public ActionResult GetNewSubObject()
{
SubObject subObject= new SubObject();
return PartialView("~/Views/TestCase/EditorTemplates/SubObject.ascx", subObject);
}
And, finally, I added this JQuery script:
function AddNewSubObject(subObjectListDiv) {
$.get("/TestCase/GetNewSubObject", function (data) {
//there is one fieldset per SubObject already in the list,
//so this is the index of the new SubObject
var index = $(subObjectListDiv + " > fieldset").size();
//the returned SubObject prefixes its field namess with "[0]."
//but MVC expects a prefix like "SubObjects[0]" -
//plus the index might not be 0, so need to fix that, too
data = data.replace(/name="\[0\]/g, 'name="SubObject[' + index + "]");
//now append the new SubObject to the list
$(subObjectListDiv).append(data);
});
}
If someone has a better way to do this than kludging the MVC syntax for nested objects onto a returned View using JQuery, please post it; I'd love to believe that there is a better way to do this. For now, I'm accepting my answer.

How can I make ASP.NET MVC 2 persist submitted form values across multiple submits?

Say I have a strongly-typed view of ViewPage<Song> and some additional fields in the form of create/edit scenarios that are not directly part of the Song entity (because I have to do some parsing before I fetch the composers from a foreign table and create the bridge entities SongComposers).
public ActionResult Create(Song song, string composers) {
if (ModelState.IsValid) {
// redirect to details
}
// return a view with errors
return View(song);
}
And in the view
<% using (Html.BeginForm()) { %>
<%= Html.EditorForModel() %>
<div class="editor-label"><label for="composers">Composers</label></div>
<div class="editor-field"><input id="composers" type="text" name="composers" /></div>
<% } %>
Now when I try to create a food and get validation errors, the previously entered form values for fields in Html.EditorForModel get filled properly but the composers field is blank after a submit. How can I fix this (ie. make it so that it "remembers" what the user wrote in the composers field)?
ViewData["composers"] = composers;