Marionette JS 3: ui has string selector after second show view - view

The problem is that after the second show view. this.ui.uielemnet return not an element but only a string selector. Events and other logic works well but i cant get element after secondshow vie. In the firstshow view` everything works as planed.
code is below. i add console log for explain. CoffeeScript)
Router:
class App.Routers.PanelRouter extends Marionette.AppRouter
initialize: (options = {}) ->
#mainView = options.cpView
routes:
'sbis-docs(/)': 'sbisDocShow'
'sbis-send(/)': 'sbisSendShow'
sbisDocShow: ->
view = new App.Views.SbisDoc
#mainView.getRegion('childRegion').show view
view.showTable()
sbisSendShow: ->
view = new App.Views.SendSbis
#mainView.getRegion('childRegion').show view
part of view
class App.Views.SendSbis extends Marionette.View
template: _.template(App.Templates.SbisSend);
initialize:() ->
vent.on('event:change-search-method', #changeSearchMethod)
vent.on('event:change-send-method', #changeSendMethod)
changeSearchMethod: (data) =>
if data.checked
#ui.cust.attr('placeholder', 'Customer ID')
#ui.labelCust.text('Номер договора')
else
#ui.cust.attr('placeholder', 'Логин')
#ui.labelCust.text('Логин пользователя')
changeSendMethod: (data) =>
console.log #ui.month
if data.checked
#ui.month.prop('disabled', false)
else
#ui.month.prop('disabled', true)
ui:
sendDocs: '#send-docs'
form: '#form-docs'
cust: '#cust'
year: '#year'
month: '#month'
labelCust:'#label-cust'
Other view:
class App.Views.SetupSend extends Marionette.View
template: _.template(App.Templates.SetupSend)
onAttach: ->
#ui.checkboxes.bootstrapToggle()
ui:
search: '#search-method'
send: '#send-method'
checkboxes: 'input[type=checkbox][data-toggle^=toggle]'
events:
'change #ui.search': 'changeSearchMethod'
'change #ui.send': 'changeSendMethod'
changeSearchMethod: (e) ->
vent.trigger('event:change-search-method', e.target)
changeSendMethod: (e) ->
vent.trigger('event:change-send-method', e.target)
In first time in changeSendMethod: (data) console log is
[input#month.form-control, prevObject: r.fn.init[1]]
But when i change route and comeback again console.log is
#month
If i change #ui.month.prop('disabled', false) on $(#ui.month).prop('disabled', false) it will be work. But i don understand why it happens and how i can fix it.

Well, the problem was that after new show view append new vent.on('event:change-search-method', #changeSearchMethod)
solve in my case
onDestroy: () ->
vent.off('event:change-search-method', #changeSearchMethod)
vent.off('event:change-send-method', #changeSendMethod)

Related

How to avoid stacking navigation history in tab-bar states

Tab A - Tab B - Tab C
States like below;
tabs.a, tabs.b, tab.c
I want to close app like there is no navigation history when switching in each of tab states
For example: I was in Tab A then I clicked to Tab B and then I clicked to Tab C from now on if user pushes back button the app should close. In normal behaviour navigation history stacks up and if I push back button I'll go to Tab B from Tab C. How to avoid this behaviour
Below is my codes;
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
.state('tabs.a', {
url: "/a",
views: {
'a-tab': {
templateUrl: "templates/a.html",
controller: 'AController'
}
}
}).state('tabs.b', {
url: "/b",
views: {
'b-tab': {
templateUrl: "templates/b.html",
controller: 'BController'
}
}
}).state('tabs.c', {
url: "/c",
views: {
'c-tab': {
templateUrl: "templates/c.html",
controller: 'CController'
}
}
});
<ion-tabs class="tabs-royal tabs-striped">
<ion-tab title="A" href="#/tab/a">
<ion-nav-view name="a-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="B" href="#/tab/b">
<ion-nav-view name="b-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="C" href="#/tab/c">
<ion-nav-view name="b-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
You can intercept the back button in each of your controllers.
From the documentation:
registerBackButtonAction(callback, priority, [actionId]) Register a
hardware back button action. Only one action will execute when the
back button is clicked, so this method decides which of the registered
back button actions has the highest priority.
For example, if an actionsheet is showing, the back button should
close the actionsheet, but it should not also go back a page view or
close a modal which may be open.
The priorities for the existing back button hooks are as follows:
Return to previous view = 100 Close side menu = 150 Dismiss modal =
200 Close action sheet = 300 Dismiss popup = 400 Dismiss loading
overlay = 500
Your back button action will override each of the above actions whose
priority is less than the priority you provide. For example, an action
assigned a priority of 101 will override the 'return to previous view'
action, but not any of the other actions.
In your controllers you can register a listener for the back button and exit if it has been pressed:
.controller('AController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
})
.controller('BController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
})
.controller('CController', function($scope, $ionicPlatform){
var deregister = $ionicPlatform.registerBackButtonAction(
function () {
ionic.Platform.exitApp();
}, 100
);
$scope.$on('$destroy', deregister)
});
NOTES:
Your last tab (C TAB) should have the name: c-tab:
<ion-tab title="C" href="#/tab/c">
<ion-nav-view name="c-tab"></ion-nav-view>
</ion-tab>
I have done it with a simple way
Added a function in controller scope of tabs state
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html",
controller: function($scope, $ionicTabsDelegate, $ionicHistory) {
$scope.rt = function(e, index) {
$ionicTabsDelegate.select(index);
//e.preventDefault();
$ionicHistory.nextViewOptions({historyRoot:true});
}
}
})
and added ng-click on each ion-tab directive in tabs.html template like below;
<ion-tab ng-click="rt($event, 0)" title="A" href="#/tab/a">
The second parameter of rt function is the index of tab
I used $ionicHistory.nextViewOptions({historyRoot:true});
From the documentation
nextViewOptions()
Sets options for the next view. This method can be
useful to override certain view/transition defaults right before a
view transition happens. For example, the menuClose directive uses
this method internally to ensure an animated view transition does not
happen when a side menu is open, and also sets the next view as the
root of its history stack. After the transition these options are set
back to null.
Available options:
disableAnimate: Do not animate the next transition.
disableBack: The next view should forget its back view, and set it to null.
historyRoot: The next view should become the root view in its history stack.
That way I achieved what I want

How to use two different collection in CompositeView

I am new to Marionette.
I am trying to create a view in which I need to show a dropdown and a table.
Dropdown is rendered from a collection. and based on value selected in dropdown I need to render collection in table.
Can you please tell me how can I achieve this kind of view ?
Thanks
**UPDATE**
I tried to achieve this thing like
http://jsfiddle.net/H8AZY/17/
var compositeView = Marionette.CompositeView.extend({
template : Handlebars.compile($("#sample-template").html()),
itemView: itemview,
itemViewContainer: 'tbody',
templateHelpers: function(){
var helpers = {};
console.log(this.coll.models);
helpers.users = this.coll.models;
return helpers;
},
triggers: {
'change select': 'selectName'
},
ui:{
select: 'select'
},
onSelectName: function() {
console.log(this.ui.select.val());
var newModel = this.coll.findWhere({name: this.ui.select.val()});
//this.collection = new Backbone.Collection(newModel.get('res'));
this.collection.reset(newModel.get('res'));
},
initialize: function(options) {
this.coll = options.coll;
this.collection = new Backbone.Collection();
}
});
Is it a good way to achieve what I want ?
There're two ways you can accomplish this.
You can just create the DOM manually.
class MyCompositeView extends Marionette.CompositeView
ui:
"select" : "select.my-select"
onRender: ->
_.each #options.states, (state) =>
$option = $("<option>", { id: state.id,
value: state.get("name") })
this.ui.select.append($option)
view = new MyCompositeView({collection: this.collection, states: stateCollection });
OR you can create an entire CollectionView for your select:
class StateView extends Marionette.ItemView
tagName: "option"
class StateCollectionView extends Marionette.CollectionView
tagName: "select"
itemView: StateView

Updating button attribute in a view from controller - Sencha Touch

I have a simple form in a view and I have a field that looks like this:
xtype: 'numberfield',
label: 'Number',
name: 'num',
disabled: true
This field is in a 'formpanel'.
I am trying to set disabled to false when the form button is pressed (enable the field).
Now, there is a button in the form that triggers a function in the view (onButtonTap) and fires a function in the controller (enableField) and sends the panel and values to it:
onButtonTap: function(button, e, eOpts) {
var panel = button.up('formpanel')
var values = panel.getValues();
panel.parent.fireEvent('enableField', panel, values);
}
And in my controller this is enableField:
enableField: function(panel, values) {
panel.config.items[0].items[1].disabled = false;
}
I am sure my controller works fine and the function enableField is actually fired, but nothing happens to the button and it stays disabled..
What am I missing?
In the controller(within refs) add the following code to get the 'numberfield' to be enabled:
refs{
numberField: 'numberfield[name="num"]'
}
And on button tap enable the field by ths:-
onButtonTap: function(button, e, eOpts) {
this.getNumberField().enable();
}

MVC 4 - Passing view model from view page to jQuery popup and back again

I have a view that is bound to a view model. On that view I have a link that will popup a modal jquery dialog (using a partial view).
What I need is to be able to pass the model to the model popup, update it, then pass it back to the view page.
I have the modal popups loading with an action method in my controller (partial view). But struggling with passing the model to it.
Any suggestions?
Thanks so much in advance.
Script (on view page):
// ZipLocator modal popup
$(function () {
$('#ZipLocatorDialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
draggable: false,
title: 'hi there',
modal: true,
show: { effect: 'blind' },
open: function (event, ui) {
// Load the ZipLocator action which will return the partial view _ZipLocator
$(this).load('#Url.Action("ZipLocator", "Shop", New With { .area = "Shop"})');
},
buttons: {
"Close": function () {
$(this).dialog('close');
}
}
});
$('#ZipLocatorOpener').click(function () {
$('#ZipLocatorDialog').dialog('open');
});
});
Controller Action for partial view:
<HttpGet()>
<Compress()>
Public Function ZipLocator(model As ShopModel) As ActionResult
Return PartialView("~/Areas/Shop/Views/Shared/Partials/Popups/_ZipLocator.vbhtml", model)
End Function
As I said, the jQuery modal popup is working, I am just having a hard time passing my model to it.
Step One is to pass the model TO the partial view (jQuery modal popup).
Step Two is to pass the updated model back to the view after the dialog is dismissed.
After some documentation reading and further research, there is a data parameter for the jQuery UI dialog.
// ZipLocator modal popup
$(function () {
$('#ZipLocatorDialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
draggable: false,
title: 'hi there',
modal: true,
**data: $("#ShopPane").serialize(),**
show: { effect: 'blind' },
open: function (event, ui) {
// Load the ZipLocator action which will return the partial view _ZipLocator
$(this).load('#Url.Action("ZipLocator", "Shop", New With { .area = "Shop"})');
},
buttons: {
"Close": function () {
$(this).dialog('close');
}
}
});
$('#ZipLocatorOpener').click(function () {
$('#ZipLocatorDialog').dialog('open');
});
});
You will need to use an AJAX POST to send a 'complex' model to your controller action - GET won't work (which is what .Load is using) .
Alternatively, it would be more simple to just modify the parameters of the ZipLocator action method so that it accepts 'simple' objects like strings, and then instantiate the complex object within the action method.
I don't know the equivalent in VB, but in C# you would modify your action like this:
[HttpGet]
public ActionResult(string areaName)
{
var model = new ShopModel { Area = areaName };
Return PartialView("~/Areas/Shop/Views/Shared/Partials/Popups/_ZipLocator.vbhtml", model);
}

mvc view insert into wrong "DOM" telerik window

Apologies in advance if this becomes a very long question...
Background Info
I have an MVC 3 application, using Telerik components and this particular issue is specific (I think) to the Window() component.
From my main view (Index.cshtml) I executing an ajax request to return a partial view which is what I am populating the contents of my window with. This is the jquery which is executing the request:
var url = '#Url.Action("GetAddPart", "Jobs")';
var window = $("#Window").data("tWindow");
var data = $("#indexForm").serialize();
window.ajaxRequest(url, data);
window.center().open();
the controller action is:
[HttpGet]
public ActionResult GetAddPart(MDTCompletedJobM model)
{
// show the AddPart window
//TryUpdateModel<MDTCompletedJobM>(model);
model.ActionTakenList = ActionTakenList;
model.ProblemTypes = ActualProblemList;
var addPartM = new MDTAddPartM() { CompletedJobM = model };
return PartialView(string.Concat(ViewDefaultUrl, "AddPart.cshtml"), addPartM);
}
this opens my window hunky dory.
in my partial view i have a form with two or three fields and an "Add", "Cancel button. For the sake of brevity I'll just show what I think are the relevant parts of the partial view, but i can produce the entire view if need be:
<div id="resultDiv">
#using (Html.BeginForm("AddPart", "Jobs", FormMethod.Post, new { id = "addPartForm", name = "addPartForm" }))
{
** layout components removed from here **
<input type="button" value="Add" class="t-button" id="btnAdd"/>
<input type="button" value="Cancel" class="t-button" id="btnCancel"/>
<p />
<div id="progressdiv">
</div>
}
</div>
is the "top level" tag in the partial view.
my jquery to handle the Cancel button is:
$("#btnCancel").click(function () {
var window = $("#Window").data("tWindow");
window.close();
});
In my main view, I have a submit button, which when completed effectively reders the main view "disabled" or displays errors. The action for this submit button returns the main view:
Controller's action snippet:
if (ViewData["DoPayJobWarningStr"] == null)
return RedirectToAction("GetAutoDispatchJob", new { autoDispatchJob = model.JobReferenceNumber});
else
return View(string.Concat(ViewDefaultUrl, "Index.cshtml"), tmpModel);
My actual problem
For a specific example I am using, I am expecting ViewData["DoPayJobWarningStr"] NOT to be null, there the return View(...) will be executed.
if I execute this action (for the submit button) without opening the window, my view returns correctly and the page is updated to show the warning message. However, if I open the window first then execute the submit button, the View isn't updated on the page, but seems to be placed into the Window's html. ie, if I hit the submit button (nothing happens), then click on the button which opens the Telerik window, I briefly see the View returned by the submit Action being shown before it's updated with what the Partial View should contain. I don't understand at all how or why the returned View is being placed there?
Things I've tried:
Commenting out the ajax request (window.ajaxRequest(url, data);) fixes the issue (even though I obviously have a blank partial view to look at).
Not making the Partial View a "Form" doesnt' work
No matter how I "close" the window, the view is still placed within there. eg clicking the x in the top right hand corner
Using Firebug, the HTML after the submit button is clicked is not updated.
Rather than using "window.ajaxRequest(url, data)", i've also tried (with the same result):
$.ajax({
type: "GET",
cache: false,
url: url,
data: $("#indexForm").serialize(),
success: function (data) {
var window = $("#Window").data("tWindow");
window.content(data);
window.center().open();
$("#progress").html('')
},
error: function (e) {
alert(e.Message);
}
});
Is it all possible to determine what I am doing wrong? Is it the ajax request? Only assuming that because removing it fixes the issue, but there might be more to it than that.
Thanks and of course if you need more info, ask :)
Thanks
EDIT
After suggestions from 3nigma, this is what I've updated to (still no luck)...
Telerik window definition:
#{Html.Telerik().Window()
.Name("Window")
.Title("Add Part")
.Draggable(true)
.Modal(true)
.Width(400)
.Visible(false)
.Height(270)
.ClientEvents(e => e.OnOpen("onWindowOpen"))
.Render();
}
jquery function which is an OnClick event for a button:
function AddBtnClicked() {
$("#Window").data('tWindow').center().open();
}
the onWindowOpen event:
function onWindowOpen(e) {
//e.preventDefault();
var data = #Html.Raw(Json.Encode(Model));
var d2 = $.toJSON(data);
$.ajax({
type: 'GET',
url: '#Url.Action("GetAddPart", "Jobs")',
data: d2,
contentType: 'application/json',
success: function (data) {
var window = $("#Window").data("tWindow");
window.content(data);
$("#progress").html('');
},
error: function (xhtr, e, e2) {
alert(e +'\n' + xhtr.responseText);
}
});
};
OK.
Issue was related to this line in the Partial View:
<script src="#Url.Content("~/Scripts/ValidationJScript.js")" type="text/javascript"></script>
As soon as I took that out, it all works. Not sure why that was causing the issue - I don't think it had been previously been loaded but maybe it had which was causing the problem.
Thanks to 3nigma for your thoughts, nonetheless!

Resources