I have a Hottowel application and a Durandal modal dialog for creating a new entity. In it's viewmodel I have create and cancel functions, which both call close on success. The problem is that modal doesn't close when I call close from another function. It does close when I call it directly.
The code:
var close = function () {
dialog.close(this);
};
var cancel = function () {
datacontext.cancelChanges();
close();
};
var create = function () {
return datacontext.saveChanges()
.then(close);
};
What do you mean it doesn't work when you call it from another function? Are you sure that your context is still the same when you are calling it?
var close = function () {
var self = this;
dialog.close(self);
};
Try to update your close function to this and if it still isn't closing then could you please explain where you are calling it that it isn't closing from? From inside the same view model, from another view model, which function, etc...
Related
I have a simple scenario, a button is pressed and the function onSearchExisting is executed. In the function I open a dialog which contains a table. The data for the table I fetch in the onSearchExisting function. Since the data fetching takes some time, I would like to set the button which triggers this function to busy.
The code looks like this in the function:
onSearchExisting : function() {
var oButton = this.getView().byId("searchButton");
oButton.setBusy(true);
oButton.setBusyIndicatorDelay(0);
var oView = this.getView();
var oDialog = oView.byId("dialog2ID");
if (!oDialog) {
oDialog = sap.ui.xmlfragment(oView.getId(),"xxx.view.fragment.SearchExisting",this);
oView.addDependent(oDialog);
}
var oDataModel = new
sap.ui.model.odata.ODataModel("/sap/opu/odata/xxxx", true);
this.getView().byId("tableSearchFrgId").getBinding("items");
oButton.setBusy(false);
oDialog.open();
},
The button is not set to busy, when I press it, what am I doing wrong?
Binding happens asynchronously, so oButton.setBusy(false); will get executed immediately after oButton.setBusy(true);.
I would suggest you use 'dataReceived' event of the binding and write the oButton.setBusy(false); inside the event handler of this event.
Read more here. https://help.sap.com/saphelp_nw751abap/helpdata/en/1a/010d3b92c34226a96f202ec27e9217/content.htm
By the time the setBusy(false) statement is executed, only few milliseconds have passed. You should put this statement in a success function of the oData call.
An oData call is async, so next line is immediatly executed even if the data is not retrieved yet.
I upgraded the kendo library to the 2014Q1 framework which had a few nice features that they were adding, however when I did that it broke any widget (grid, tabStrip, select lists, etc.) from rendering at all. I tracked it down to the layout/view not being able to activate the widget without being wrapped in a setTimeout set to 0. Am I missing something key here or did I build this thing in an invalid way?
http://jsfiddle.net/upmFf/
The basic idea of the problem I am having is below (remove the comments and it works):
var router = new kendo.Router();
var mainLayout = new kendo.Layout($('#mainLayout').html());
var view = new kendo.View('sample', {
wrap: false,
model: kendo.observable({}),
init: function() {
// setTimeout(function(){
$("#datepicker").kendoDatePicker();
// }, 0);
}
});
mainLayout.render('#container');
router.route('/', function() {
mainLayout.showIn('#app', view);
});
router.start();
Admittedly, I don't fully understand it, but hope this helps.
Basically when you try to init the #datepicker, the view elements have not been inserted into the DOM yet. You can put a breakpoint inside the init function, when it hits, check the DOM and you will see that the #app is an empty div, and #datepicker does not exist yet (at least not on the DOM).
kendo.Layout.showIn seems to need to exit in order for the view to finish rendering, but when it initializes the view's elements, it thinks the render is done and init is triggered incorrectly ahead of time. The setTimeout works because it runs the kendoDatePicker initialization asynch, the view is able to finish rendering before the timeout function.
Workarounds...
Trigger the view rendering from the view object itself:
var view = new kendo.View('sample', {
init: function() {
$("#datepicker").kendoDatePicker();
}
});
router.route('/', function() {
view.render('#app');
});
Select and find the datepicker from the view object itself:
var view = new kendo.View('sample', {
init: function() {
view.element.find("#datepicker").kendoDatePicker();
}
});
router.route('/', function() {
mainLayout.showIn('#app', view);
});
Near the bottom of this thread is where I got the idea for the 2nd option. Maybe someone else can come around and give a better explanation of whats going on.
I create an object that returns textBox(), which could change their properties depending on the user's actions. However, once I put the function doChange(e) inside the object as a method like this:
function textBoxExt() {
...
this.doChange = function(e) {...}
...
}
my code returns an error: Cannot find a function doChange()...
I tried different ways to declare a function as a method in my object, but none of them worked. Please tell me, how do I modify the code below to move doChange(e) inside the object as a method. It is possible for functions that calls by handlers?
var style = {
modified: {color: 'black', backgroundColor: 'yellow', },
};
function textBoxExt() {
var app = UiApp.getActiveApplication();
var changeHandler = app.createServerHandler('doChange');
var box = app.createTextBox();
box.addValueChangeHandler(changeHandler);
this.init = function(id) {
return box.setId(id);
}
}
var doChange = function(e){
var app = UiApp.getActiveApplication();
app.getElementById(e.parameter.source).setStyleAttributes(style.modified);
return app;
}
function doGet() {
var app = UiApp.createApplication();
app.add(new textBoxExt().init('box1').setText('text1'));
return app;
}
You cant do this with gas. Handlers are passed as text. Besides objects only exist during the current handler so it cant possibly be attached to an object from a previous server call.
Modals are turning out to be more difficult than I thought :/
Got the modal loading up a view / view modal properly, clicking the save button saves the information (I do get a 'Should be Empty : []' from Q.js but apparently this isn't a problem?) the problem I am having is probably related to promises but if it is I can't find it.
Parent's view model -
var createNew = function () {
app.showModal(tfcreate).then(function (modalResult) {
if (!modalResult) { return false; }
var templateId = modalResult;
router.replaceLocation('#/templateformedit/' + templateId);
});
};
Modal's view model -
var cancel = function () {
this.modal.close(false);
};
var save = function () {
isSaving(true);
setRevisionInfo();
datacontext.saveChanges()
.then(alertMe)
.fail(initFailed)
.fin(complete);
function setRevisionInfo() {
templateForm().revisionLevel(1);
templateForm().createdById(shell.currentUser().id());
templateForm().lastRevisedId(shell.currentUser().id());
var nowDT = moment().format('LL');
templateForm().lastRevisedDT(nowDT);
templateForm().createdDT(nowDT);
}
function alertMe() {
return console.log('done'); // <<< This is firing ok
}
function complete() {
isSaving(false);
this.modal.close(templateForm().id()); // <<< Breakpoint reaches here just fine
}
};
If I press the cancel button which is bound back to cancel() it closes just fine, if I click the save button it hits save(), saves the object properly, and reaches all breakpoints but never closes. If after I save I press cancel it closes just fine again. I have tried calling cancel() during the complete() function and it reaches the statement, but again does not close. Any ideas???
Note : I can call router.replaceLocation from the modal and it will change the view just fine but the modal persists to the next view.
Edit : I added another button 'close' that is disabled until isSaving is finished and hasChanges is false and that lets me close it and everything just fine, but that shouldn't be necessary, right?
Per request:
Are you sure that this in complete() is still your vm context? Try var self=this; at the top of save() and in complete() self.modal.close(...)
I understand that this is a probably a noob-ish question, but I've had no luck with the other threads I've found on the same topic.
I've devised a workaround to hack a views exposed filter to hide and show products with a stock count of "0". The exposed filter for the stock count (input#edit-stock) is hidden with CSS and inside a custom block is a link to manipulate the form and trigger the query (with ajax). This is working great, but with one exception - after resetting the form with the views-provided "reset" button, toggle() will not rebind properly to the link, and click won't fire the first time. Works fine on the 2nd click. I'm sure that the solution is very simple, but I'm at a loss..
How to rebind toggle() effectively?
Sorry, I'm unable to provide a live example. Many thanks for any input.
CUSTOM BLOCK:
<a id="toggle" href="#">exclude</a>
JQUERY:
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
$('a#toggle').unbind('toggle').toggle(include, exclude).html('exclude');
});
});
if i get the problem right you need to reset the toggle. Why instead of unbind toggle and rebinding it you just don't simulate a click if the link is == to include?
$(document).ready(function () {
var include = function () {
$('input#edit-stock').attr('value', 0).submit();
$('a#toggle').html('include');
};
var exclude = function () {
$('input#edit-stock').attr('value', '').submit();
$('a#toggle').html('exclude');
};
$('a#toggle').toggle(include, exclude);
$('input#edit-reset').live('click', function (event) {
//if the link is include, click it so that it resets to exclude, else do nothing
if ($('a#toggle').html() == 'include'){
$('a#toggle').click();
}
});
});
fiddle here: http://jsfiddle.net/PSLBb/
(Hope this is what you were looking for)