I have the following setup: knockout, phonegap, JQM.
My application is based on http://propertycross.com/jquery-mobile/
until now my app was a 'tree' structure - i.e. the user click a menu entry and than when he wanted a different menu entry he had to click 'back' button to navigate back to the main menu.
but now I have a requirement that the user could jump to any menu entry from any where in the app.
but this mess up the 'back' functionality, since the view model is overridden by the new data...
i.e.
scenario A: I display the menu -> user click entry1 -> I applyBindings model1 to view1 -> view1 is displayed with a link to entry2 -> link is clicked -> I change the value in model1 -> view1 is displayed with new data -> user click back -> view1 is display but with the wrong data
I tried to solve it by applyBindings the new data, but this causes the data-bind handler to fire multiple times.
i.e.
scenario B: I display the menu -> user click entry1 -> I applyBindings model1 to view1 -> view1 is displayed with a link to entry2 -> link is clicked -> I applyBindings model2 to view1-> view1 is displayed with new data -> click handler are fire multiple time...
I could block the multiple execution with a flag - but I don't want to do it for EVERY function in my code...
I think there might be a solution using knockout template, but I couldn't find a proper example...
So my questions are:
Is knockout/phonegap/JQM not suited for this scenario: a cyclic app structure + back button ? or am I missing something?
Can it be solved with templates? how?
Any alternative solution?
My solution is: generate views dynamically with jQuery append(), example:
$.each(acts, function (key, act) {
if (!that.missionListViewModels[act.id]) {
that.missionListViewModels[act.id] = new MissionListViewModel(application);
$("body").append('<div data-theme="b" data-role="page" id="missionListView'+act.id+'" data-url="missionListView'+act.id+'" style="text-align:left;"><div data-bind="template: { name: \'missionListViewTemplate\', data: missionListModel }"></div></div>');
}
}
NOTE:
I keep an array (that.missionListViewModels) with reference to the dynamically created missionListViewModels for future reference.
in order to keep the code in the append() short I use ko template, but this is not necessary.
The JQM/KO templates does not support the append() well:
the data-url, which was normally generated by the JQM was missing, therefore I had to add it manually.
data-i18n inside the template did not work, I had to use data-bind="text: ..." instead
'with' inside the template did not work, I had to change the code to avoid it.
Related
I am using MVC3, C#, Razor, EF4.1, SQLServer 2008.
I have a parent form with a dropdown for "Suppliers". I wish to add a "quick add" link/button that enables the user to quickly add a supplier to the DB which is then available in the dropdown for selection. At present this is achieved by
Parent Page -> Add Supplier Page -> Parent Page(Page Refresh)
Of course on return to the parent page, it refreshes and removes all non saved data - which is a problem. It would be better to have a popup window which then saves the suppliers and then just refreshes the dropdown portion of the parent page form. So I believe I am seeking an approach to:
Parent Page -> Popup(Modal) -> DB Save -> Refresh DropDown in Parent Page (Ajax???) -> close Modal popup.
I would appreciate guidance on the above, as I am a little stuck on the best practice and hopefully simple approach to this.
Many thanks.
I normally do something like this:
Create an 'Add' button that will display a popup. (I use jQuery dialogs. They are simple, free, and easily to implement by just calling .dialog on a div). Inside this dialog have the appropriate fields needed to create a new supplier. Have a 'Save' button in this dialog and have it wired up to a AJAX post. (Again this is very simple using jQuery)
If you do use jQuery its as simple as submitting that form to your controller action that will then call you data access layer to save the new supplier entity. When the AJAX call comes back successfully you can reload the contents of the supplier grid with another AJAX post. All the 'Magic' comes from implementing AJAX really which will allow for you to retain the users input and not reload the whole page. The AJAX call that is executed after the user enters in a new Supplier and clicks save would look something like this:
In your JavaScript:
$.ajax({
url: "ControllerName/SaveNewSupplier",
Data: $('#YourAddNewSupplierFormName').serialize(),
Type: "POST"
Success: function(result) {
// this is what will get called after a successful save and return of your action method on your controller. This is where you will put the call to repopulate the supplier list with the updated list.
UpdateSupplierList(); // This function is created below
}
});
In your controller:
Public JsonResult SaveNewSupplier (NewSupplierModel newSupplier)
{
// save your new supplier through your data access layer
// if save is successful then return
Return Json({success = true}, JsonRequestBehavior.AllowGet)
}
Then to repopulate the initial div that contains all the suppliers do something like this:
In JavaScript:
function UpdateSupplierList()
{
$.ajax({
url: "ControllerName/GetAllSuppliers",
Type: "GET"
Success: function(result) {
$('#SuppliersDiv').html(result.suppliers)
}
And in your controller:
// remember that a lot of this is pseudo code and your will have to implement it better for your situation. But basically its just:
Public JsonResult GetAllSuppliers()
{
var suppliers = db.GetSuppliers()
return Jason({suppliers = suppliers}, JsonRequestBehavior.AllowGet);
}
EDIT: If you are updating a SelectList via jQuery then this article is almost identical to what I explained but goes into much more detail on updating the select list. Hope this helps.
http://www.joe-stevens.com/2010/02/23/populate-a-select-dropdown-list-using-jquery-and-ajax/
What would be the best way to display data from Grails database in JQuery UI tabs? What I would like is to have a tab interface and on each tab is a list of the records from a different domain. For instance, Tab1 displays the record list from Domain1, Tab2 displays the record list from Domain2, etc.
I have the JQuery UI tab interface set up and working and am currently using createLink to call the method from the controller to return the model of the appropriate domain. The tabs look like this:
<div id="tabs">
<ul>
<li>Hardware records</li>
<li>Model records</li>
<li>Building records</li>
</ul>
</div>
The method from the controller looks like this:
def listHardware() {
[hardwareList:Hardware.list(), hardwareInstanceTotal:Hardware.count()]
}
I've also played around with rendering a whole GSP within the tab by using "render(view:'HardwareList', model:[hardwareList:Hardware.list(), hardwareInstanceTotal:Hardware.count()]", but that takes a VERY long time (at least 5 seconds) to load each time the tab is selected and is not at all ideal, especially if it were to take that long for each tab.
UPDATE
As noted in one of my answers to Rimero's answer below, I was able to use templates to display tables of my domains' data. I'm also trying to implement pagination on each tab using the tag, but each time I click on one of the pages to view another page, it takes me to the full template itself outside of the tab interface. Any thoughts on how to format the tag so that everything stays within the tab??
Here's my suggestion:
You can fetch everything at once in your controller in your index method for example.
You can implement your tab contents as templates
(g render template). Each tab == 1 template.
You can fetch your domain objects buildingList,
etc. from the index method of your controller.
The g:render template code for each tab may only need to be passed a map or a collection for rendering.
In this case you don't need hyperlinks to controllers endpoints. You just keep anchors to the tab(div id) as in the default example here -> http://jqueryui.com/tabs/.
UPDATED ANSWER
As you said that sending all the data at once takes a long time, you could fetch it asynchronously. If possible populate the data only for the first tab directly.
Create a business method for each tab, that will return the model as JSON, data is only fetched if not already retrieved from the server (Need to keep state or see for example if the tab id has some DOM nodes.
Using JQuery, when the DOM is ready, get the current tab and if you didn't fetch the data for the first tab eagerly, fetch it at this moment with the busy image spinning.
As soon as you select a new tab, you need to check if the data was already fetched, if not, you send an ajax call and your callback function populate the data in the tab div container for example.
Hope it helps.
I have a view, say show.js.erb. And I have a link in another view such that
link_to "MyLink", my_object_path, :remote => true
successfully returns the show.js.erb view. My question is, from within that view, is there any way to access the element that triggered the AJAX call without having to resort to generating an id specific to individual elements a la ...
I want to be able to use this view callback to open a small dialog next to whatever element was clicked on, but I can't seem to find a way to access the triggering element.
I tried using $(this) but that doesn't work.
I'd like to do something along the lines of
$(this).after("some new html here");
My solution was to bind a pre-submit class to the element, in my case a popup modal window. It's a similar solution to the post linked to above in that it uses the pre-submit bindings, but tailored to use classes instead.
In public/javascripts/application.rb:
jQuery(function($) {
$(".poppable").bind("ajax:loading", function() { $(this).addClass("popped"); });
});
Then in my view for the popup content (e.g. app/views/mymodel/popup.js.erb):
var p = $(".poppable.popped");
p.removeClass("popped");
/* Do what I need to with p ... */
If this doesn't look kosher, I'm all ears but it works for now.
I have a page that displays a list with a of elements with a large number of elements, each of which has a boolean property, representing an Enabled and a Disabled state.
I need to provide the user with a link for each list item, and the link text must show the opposite status (so if the item is enabled, the link text must display 'Disable').
When the user clicks the link for a Disabled, the corresponding link text for the item must change to 'Enable' (and vice versa).
I would like to NOT reload the entire list for each click, just the text of the ActionLink itself, so my question is:
Is it possible to update just an ActionLink itself when the user clicks the link, or do I have do handle this using custom javascript?
As far as I remember, you can add HTML attributes to the "a" tag by newing up an anonymous class as the last param on most overloads.
Off the top of my head this can be written like the following:
Html.ActionLink("Name", "Action", "Controller", new { #class = 'updateId' });
(You may be able to do this with an ID which would be preferable over a class - if not just use a unique class name to avoid updating multiple items.)
Then you can use javascript to access the class "updateId" and change the inner html.
In the case of jQuery:
$("a.updateId").html("NewName");
This can be done with a custom user control contained within the element to update. A writeup of the solution can be found here. No custom client-side scripting is necessary.
I've got a list view in my MVC app that shows a check box next to each entry:
<% For Each item In Model%>
<%=Html.CheckBox("Selected", item.select_flag, New With {.onclick = "this.form.submit();"})%>
<%=Html.Hidden("ID", item.id)%>
<%=item.name%>
<br/>
<% Next%>
As you can tell from the onclick, I'm submitting the form each time a user clicks a check box. In the controller, my post action looks like this:
<AcceptVerbs(HttpVerbs.Post)> _
Function List(ByVal Selected() As Boolean, ByVal ID() As String) As ActionResult
For i = 0 To ID.Count - 1
If Selected(i) Then
[use ID(i) to update a database row]
End If
Next
Return View(GetTheListOfNamesAndIds())
End Function
So I get an array of Selected values and ID's after each checkbox click. I assumed they would correspond, but I'm finding the two arrays to be out of sync for some reason. It's also a lot of overkill to process the whole list every time a checkbox is clicked, so I'd like to revisit this whole setup.
What's the best way to set this up so that clicking a checkbox will update a specific database row? Can it be done without reloading the list each time?
Consider wrapping each "row" in it's own AjaxForm or using jQuery to do the update via AJAX, then passing the data required for the action via the route values (or form values) in the AJAX get/post. The AjaxForm will want to update some DOM element with new content, but you could get around this by having it update an error message (with nothing if there is success) rather than the actual row and doing any local changes via javascript. With jQuery AJAX you have a lot more options of how you want to handle it but you may have to implement more code on the client side.