durandaljs 2.0 navigation - durandal

I have a view with pagination. When the user clicks on a page number, I display the data for that page.
I only want the data items to be replaced so I don't want to navigate to the "next page." So what I'm doing is using the router.navigate(url, { replace: false, trigger: false }); to add the page to the browser's history, but not to trigger the navigate there.
If after I get the data, I click on the browser's back button, the URL changes to the previous one, but I don't get an event. If once I'm back in the previous page, I click the browser's forward button, I get the trigger event from that page.
Example. I'm at /# and it is displaying page 1 of the data. The user click on the "next page" link on the page. I display page 2's data, and I replace the url with /#welcome/2 Now if I click on the browser's back button the URL changes back to /# but the page doesn't trigger. If I press the browser's forward button the URL changes back to /#welcome/2 and the page triggers. Now that that has happened, I can click the back button and page one will trigger; and I can go back and forth between page 1 and page 2. If the user clicks on "page 3", the problem happens again.
If you all need a working example, I will deploy it, but currently this is only running on my local box.

IMO paging, like sorting/filtering represent the internal state of a view/widget and shouldn't be presented via routes. Consider e.g. user is on #something/3 and bookmarks the url. After deleting a couple of items there's no #something/3 any longer and the bookmark fails. Here's some more thought food on that topic http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/
Update based on comments:
activate on hitting browser back get's not called for two reason. a) welcome.js returns a singleton and b) in shell.html viewCache is set to true. When the user press browser forward it get's called because at this time route #welcome/2 from the SPA perspective is called the first time, so activate kicks in.
One way to make the system work would be to force every page change (regardless if it was initialized by SPA or browser) running through activate. Here are the required steps: Convert the singleton into a constructor, set cacheViews: false and replace click events by normal hrefs that calls the page route.
Update 2
Here's an example that combines the inPage navigation (without router involvement) with the ability to use browser back/forth navigation. init is responsible for setting up things that are common for activate and gotoPage.
Viewmodel
define(['plugins/router', 'knockout'], function( router, ko ) {
var ctor = function() {
this.pageNo = ko.observable();
this.pageData = ko.observable();
};
ctor.prototype.activate = function( page ) {
this.init(page);
};
ctor.prototype.init = function( page ) {
this.pageNo(page || 1);
this.pageData('Data for ' + this.pageNo());
};
ctor.prototype.gotoPage = function( page ) {
var url = "extras/welcome/" + page;
this.init(page);
router.navigate(url, { replace: false, trigger: false });
};
return ctor;
});
View
<section>
<h1>
Hello Durandal Pagination
</h1>
<a data-bind="click: gotoPage.bind($data, 1)" style="cursor: pointer;">Page 1</a>
<a data-bind="click: gotoPage.bind($data, 2)" style="cursor: pointer;">Page 2</a>
<a data-bind="click: gotoPage.bind($data, 3)" style="cursor: pointer;">Page 3</a>
<h2 data-bind="text: pageData"></h2>
</section>
Live example at: http://dfiddle.github.io/dFiddle-2.0/#extras/welcome

Related

Polymer 2.0 capture long press on dynamically generated paper-cards

Issue: How to select multiple paper-cards and know which ones is selected on user long press/tap on the card.
Description:
I have dynamically generated paper-cards and I render them on the page using template Dom-repeat. At present I have included checkboxes on each paper-card so that the user can select those checkbox associated with the paper-card. That way the user on the screen can select multiple cards on which I can action the next functionality.
I guess the better user experience will be that the user be able to tap or click on the paper-card and be able to hold his finger/mouse for say .5sec and be able to select that card rather than checkbox style selection.
If I am able to get a working code snippet of how a multiple paper-card selection is used then I will be able to provide a better UX for the app.
Current Code Snippet:
(here I am using a paper-icon-button to get the user selected paper-card element).
<template is="dom-repeat" items="{{itemsList}}" as="item">
<paper-card style="float:center; width: 95%" class$="
{{_computeCardColorTran(item.type)}}" data-index$="{{item._id}}">
<paper-icon-button icon="icons:arrow-drop-down" style="color:
grey;" id$="bttn#{{item._id}}" item="[[item]]" on-
tap="doSomeDiffAction">
</paper-icon-button>
<iron-image class="pad"
src="../images/image1"
preload
sizing="contain"
style="" >
</iron-image>
</paper-card>
</template>
What I wish to have (something like below) -->
<template is="dom-repeat" items="{{itemsList}}" as="item">
<paper-card style="float:center; width: 95%" class$="
{{_computeCardColorTran(item.type)}}" data-index$="{{item._id}}"
something-like-user-pressed-longed="
callFunctionUserPressedForLong"
>
<paper-icon-button icon="icons:arrow-drop-down" style="color:
grey;" id$="bttn#{{item._id}}" item="[[item]]" on-
tap="doSomeDiffAction">
</paper-icon-button>
<iron-image class="pad"
src="../images/image1"
preload
sizing="contain"
style="" >
</iron-image>
</paper-card>
</template>
And in script javascript function in dom-module I can extract the paper-card selected
function callFunctionUserPressedForLong(e){
var id = e.model.item._id;
console.log('User pressed for long time on the paper-card = '+ id);
}
function doSomeDiffAction(e){
var id = e.model.item._id;
console.log('Not a long press event. User taped or clicked paper card button. Do different action e.g. open popup. = '+
id);
}
Thanks
You have to use on-down and on-up events from Polymer and watch time diff between these two events yourself.
In example below, on-down and on-up event functions are the same for both components (paper-card and paper-icon-button). Inside the on-down function (_onDown), the current time is saved to variable. Inside on-up method (_onUp) is detection for tap/click on button (if time diff between on-down and on-up is <0.5s and event target is the element with id=bttn#{{item._id}} and long-press somewhere inside paper-card (including paper-icon-button).
_onDown(e) {
this.startTime = Date.now()
}
_onUp(e) {
let id = e.model.item._id;
//stopPropagation because this is otherwise called twice - from paper-card and from paper-icon-button
e.stopPropagation()
let id = "1"
if (Date.now() - this.startTime > 500) {
console.log(`long press somewhere inside paper-card :: id=${id}`);
} else if (e.target.id == `bttn#${id}`) {
console.log(`Not a long press event. User taped or clicked paper card button :: id=${id}`);
}
}
<paper-card on-down="_onDown" on-up="_onUp">
<paper-icon-button on-down="_onDown" on-up="_onUp">Tap me</paper-icon-button>
</paper-card>

Bigcommerce Add To Cart Pop-Up

When using bigcommerce before, we were able to choose whether or not to have a pop up or take the user to the cart whenever they clicked the "Add to Cart" button. Does anybody know if this feature has been taken out by BigCommerce or where I can find that setting now? Thank you!
Do you know if you're using the Stencil or Blueprint framework?
If you're using blueprint, you can go to "Store Setup > Store Settings > Display" and choose "Take Them to Their Shopping Cart".
If you're using stencil, that feature is hidden and you have to do customization for it to work. If your products don't have any options, you can follow the instructions on this page: https://support.bigcommerce.com/articles/Public/How-can-I-add-a-product-to-the-cart-with-a-link/#add-to-cart.
However, if you have options, this won't work because it doesn't updated the sku in the url. What i did to get this to work was to edit the product-details.js
First you need to download the theme in order to edit the js file. Then, starting on line 234, you'll see the following code:
// Open preview modal and update content
if (this.previewModal) {
this.previewModal.open();
this.updateCartContent(this.previewModal, response.data.cart_item.hash);
} else {
this.$overlay.show();
// if no modal, redirect to the cart page
this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);
}
Directly under the comment, add /* and then go down one line under the closing brace of the else statement (}) and add */ to close the long comment. The code will now look like this:
// Open preview modal and update content
/*
if (this.previewModal) {
this.previewModal.open();
this.updateCartContent(this.previewModal, response.data.cart_item.hash);
} else {
this.$overlay.show();
// if no modal, redirect to the cart page
this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);
}
*/
this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);
Let me know if this helps!
Just FYI I went through a similar problem and found that the "Ask a Design partner" forum gave me my answer. The answer I used was from this post:
https://support.bigcommerce.com/s/group/0F913000000HLpWCAW/ask-a-design-partner
But to help I will pull out what they said:
"If you want to remove the popup, you will need to edit the theme files, navigate to the templates/components/products/product-view.html file, and comment out (or remove )this code at the bottom of the file:
<div id="previewModal" class="modal modal--large" data-reveal>
<a href="#" class="modal-close" aria-label="{{lang 'common.close'}}" role="button">
<span aria-hidden="true">×</span>
</a>
<div class="modal-content"></div>
<div class="loadingOverlay"></div>
</div>
Hi You need to do this :
1. Login to admin-end then go to store setting
2. From top tabs choose display tab
3. Find the 'Add to Cart' Action choose what you want pop window or redirection to the cart page.
4. hit the save button.
Check image:
Thanks

How to keyboard navigate to reCAPTCHA in a modal dialog?

I need to open Google's latest reCAPTCHA widget in a popup (modal) dialog, a Dojo Dialog in my case, and I've got that working fine, but I just realized that the user cannot keyboard navigate to it.
When the reCAPTCHA widget is displayed in the main view, not a modal dialog, then of course the user can easily keyboard navigate to it.
Has anyone found a way to set focus on the reCAPTCHA widget so that the user can access it without a mouse when the reCAPTCHA is in a Dojo Dialog?
I did see that reCAPTCHA is generated within an <iframe>. Is that part of the hurdle - that keyboard navigation can't reach content within an iframe? I've even tried to call document.getElementById("recaptcha-anchor") since I saw that that's the id of the <span> that holds the "checkbox" - but that is returning null. How to reach an element within an iframe?
I have a jsfiddle example available for demonstration at
https://jsfiddle.net/gregorco/xqs8w5pm/5/
<script>
var onloadCaptchaCallback = function() {
console.log("jsfiddle: rendering captcha");
globalRecaptchaWidgetId = grecaptcha.render('captchaDiv', {
'sitekey' : '6LcgSAMTAAAAACc2C7rc6HB9ZmEX4SyB0bbAJvTG',
'callback' : verifyCaptchaCallback,
'tabindex' : 2
});
grecaptcha.reset();
}
var verifyCaptchaCallback = function(g_recaptcha_response) {
console.log("Response validated. Not a robot.");
};
</script>
<script src='https://www.google.com/recaptcha/api.js?onload=onloadCaptchaCallback&render=explicit' async defer></script>
<div id="testDiv">
<button type="dojo/form/Button" onClick="captchaPopup.show();">Open reCAPTCHA</button>
</div>
<div data-dojo-type="dijit/Dialog" data-dojo-id="captchaPopup" title="Human Verification" style="width:350px;">
Cannot keyboard navigate to the checkbox!
<table>
<tr>
<td>
<div id="captchaDiv"></div><br/>
</td>
</tr>
</table>
</div>
Give this fiddle a try. Normally Dijit dialogs don't work too well with iframes in them because it doesn't know how to parse the content inside an iframe. In this case, we can use some of Dojo's functions to work around it. One notable thing to point out is that I've disabled autofocus of the Dijit Dialog so that it won't automatically focus the closeNode inside the dialog.
After the dialog loads, tab>space will select the captcha.
This may help others facing similar issue, but with Bootstrap modal dialog. I found the following solution on GitHub. Add the following Javascript to override Bootstrap:
Bootstrap 3x
$.fn.modal.Constructor.prototype.enforceFocus = function () { };
Bootstrap 4x
$.fn.modal.Constructor.prototype._enforceFocus = function () { };

Issue in cjuidialog close and reopen in mutiple ajax request

i am using cjuidialog for popup a webform through ajax links.
First time it is opening nice.But after close and i navigate to another page and come to this page again without reloading the whole page but reloading a div only through multiple ajax requests,the pop up is not coming.Kindly suggest me the soluton.
I think the problem is that CJUIdialog creates s with popups inside everytime you send ajax request. So after few request you have several popup divs with the same ID. What I did I removed CJUIDialog div and its parent in every ajax request. Like this:
function remove_popup(){
if($("#popup1").length){
$("#popup1").remove();
if($("#popup1").parent().hasClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-draggable ui-resizable")){
$("#popup1").parent().remove();
}
}
}
And important to include:
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery-ui.min.js'] = false;
in the begging of a view. (not in the main view)

How to get Jquery UI tab to be blank

I have a JQuery UI tab dialog that is the detail of a Master-Detail interface. When someone selects an element in the master, the tabs all get their href's populated with URLs giving details of that selected item.
For example, see
http://www.trirand.com/blog/jqgrid/jqgrid.html and browse to Advanced->Master Detail.
But instead of updating a second grid, I'm updating the links of a jquery-ui tabs element like so:
var urls = {
0 : "/url1",
1 : "/url2",
};
jqgrid(....
onSelectRow: function(location_id) {
for (url in urls){
$('#tabs').tabs('url', url , urls[url]+location_id );
}
var selectedTab = $('#tabs').tabs("option", "selected");
$('#tabs').tabs('load', selectedTab);
}
);
$(#tabs.tabs({});
With html like:
<div id="tabs">
<ul>
<li><a id="URL1" href="blank.html">Info</a></li>
<li><a id="URL2" href="blank.html">History</a></li>
</ul>
</div>
I shouldn't have to use a blank.html dummy link. Is there something I can do (when I don't have anything selected in the master) that doesn't cause my tabs to cause a fetch and instead just be empty?
If you set the tab to be blank in your coding nothing will appear in it (obviously), but if you need to empty it on page load use this:
$(document).ready(function() {
$('#divID').empty();
});