History inside state - angular-ui-router

I`am created ionic app that has one state called master {url: /master}. There are two buttons on the state view. Each button shows hidden div with text.
I want to implement history tracking by this rules:
When user clicks on first button then url should be appended with firstOpened=true
When user clicks on second button then url should be appended with secondOpened=true
Controllers should stay the same (no re-initialization needed)
Back button of browser should undo last action, for example: If user opens first div then back button should close this div and restore url without page reload.
If history of master state is empty, then back button should restore previous state if it exsits
If i use $state.go to change url, then ionic will reinitialize state and all controllers. It looks like i move from one view to another (from one state to another), but i dont want to change the state, i want to update url and push history. I want to use same state without re-initialization.
I`am created plunker without history tracking. Can somebody help me with implementig history tracking?
script.js (see ):
angular.module('starter', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
var controller = 0;
$urlRouterProvider.otherwise("/master");
$stateProvider.state('master', {
url: '/master?firstOpened&secondOpened',
views: {
'default': {
templateUrl: 'content.html',
controller: function($scope, $ionicHistory, $stateParams, $state) {
console.log('Initing controller...');
controller = controller + 1;
$scope.controller = controller;
$scope.firstOpened = $stateParams.firstOpened
$scope.secondOpened = $stateParams.secondOpened
$scope.openFirst = function() {
$scope.firstOpened = true;
};
$scope.openSecond = function() {
$scope.secondOpened = true;
};
}
}
}
})
})

The point is, that you do not change the state on click. You are only changing the scope variables, but that doesn't mean any change to the URL or history.
To get history support, you need to change the state and put a ng-show on your sliders. I did it with ui-sref like this:
<ion-content>
<h1>Controller №{{::controller}}</h1>
<button class="button" ui-sref='master({firstOpened: true, secondOpened: false})'>Open first</button>
<button class="button" ui-sref='master({firstOpened: false, secondOpened: true})'>Open second</button>
<div style="background-color: #FF0000;" ng-show="{{firstOpened}}">
<h1>Slider 1</h1>
</div>
<div style="background-color: #00FF00;" ng-show="{{secondOpened}}">
<h1>Slider 2</h1>
</div>
</ion-content>
And your controller only needs to keep track of the stateParams, like you already did:
controller: function($scope, $ionicHistory, $stateParams, $state) {
console.log('Initing controller...');
controller = controller + 1;
$scope.controller = controller;
$scope.firstOpened = $stateParams.firstOpened;
$scope.secondOpened = $stateParams.secondOpened;
}
I've updated your plunker code here.
As you can see, I had to remove the slide animation, as it did not react properly on firstOpened and secondOpened values. But this is another issue and I am sure it's no big deal to get it to work again.

Related

How to determine view is backed in Kendo Mobile?

Is there any way to know that view is open by back?
For example
<div data-role="view" id="view-test" data-show="show">
<!-- View content -->
</div>
<script>
var show = function(e){
if(e.view.isBack())
{
console.log("Back")
// do something
}
}
</script>
Is there any method or property like e.view.isBack() ?
There are many ways to handle this, maybe you can use a global variable where you keep the last visited page or even you can add a back button handler and get the view from which the back button was pressed. Another solution would be to pass a parameter along with page navigation when going back, for example:
<a data-role="button" href="#foo?back=true">Link to FOO with back parameter set to true</a>
And on the visited page on show event you can get the parameter like this:
function fooShow(e) {
e.view.params // {back: "true"}
}
Now depending on what the parameter value is you can detect if the back button was pressed or not before reaching the page.

Ember event in one view update another?

I have a small extract from my Ember app here. My page contains a number of views each containing different data each with their own controllers.
I want a search field (in index view) to go in one view which should "talk" to the stationList controller to update the content of the stationList view. This doesn't work. I get an error: TypeError: this.get(...).search is not a function
The logging outputs the name of the contoller I've asked it to use: App.StationListController
I added a second search form inside on the StationList View. This one works just fine. The logging this time outputs a dump of the StationListController object. So I am guessing that the other search form, despite my code (in SearchFormView): controllerBinding : 'App.StationListController', is not correctly setting the controller.
So I guess my question is why not?
How can I route the change on the form field in the one view to call a funciton on another view's controller?
Here's my code:
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<div id="searchForm">search form view search:
{{#view App.SearchFormView}}
{{view App.StationSearchField}}
{{/view}}
</div>
<div id="stationList">{{render stationList}}</div>
</script>
<script type="text/x-handlebars" data-template-name="stationList">
station list view search: {{view App.StationSearchField}}
<ul>
<li>List</li>
<li>will</li>
<li>go</li>
<li>here</li>
</ul>
{{searchTerm}}
</script>
And
App = Ember.Application.create({})
App.SearchFormView = Ember.View.extend({
init : function()
{
console.log("SearchFormView init", this.get('controller'))
}
})
App.StationSearchField = Ember.TextField.extend({
keyUp: function(event) {
var searchTerm = this.value
console.log("value",searchTerm,this.get('controller'))
this.get('controller').search(searchTerm)
}
})
App.StationListController = Ember.ArrayController.extend({
content : [],
searchTerm : null,
search : function(term)
{
this.set("searchTerm",term)
console.log("searching",term)
}
});
Fiddle: http://jsfiddle.net/ianbale/8QbrK/14/
I think the controllerBinding stuff is from the older version, I don't think that works anymore.
You can use controllerFor on get('controller') in the StationSearchField.
this.get('controller').controllerFor('station_list').search(searchTerm)
But controllerFor is deprecated and may be removed. Depending on your application structure you use needs on the controller.
Another way which I am using, is to send a custom event from the View, which the Route then sends to the corresponding controller.
App.IndexRoute = Ember.Route.extend({
events: {
search: function(term) {
controller = this.controllerFor('station_list')
controller.search(term);
}
}
});
and dispatch a search event from view like so.
this.get('controller').send('search', searchTerm);
The advantage of this method is you dispatch the same event from multiple places and it would get handled in the same way.
Here's the updated jsfiddle.

Checking a checkbox to submit to a link not working in Chrome

I have a link in a razor view (.NET MVC3) which is part of a sort function which shows all records (active and archived) or the active ones (the default on page load). It works fine in Firefox. But it only works when I click on the text part of the link not when the checkbox is checked for chrome and IE. Here is the code I've used.
<a id="lnkShowAll" href="#Url.Action("showAll", "myController", new { showOnlyActive = !Model.Active })" >
<input id="chkShowAll" type="checkbox"
#if(!Model.Active){
#: checked="checked"
} >
Show All (<span class="activeFont">Active</span> / <span class="archivedFont">Archived</span> )
</a>
This is the Controller but I doubt the problem is with the controller since no call is being made to it when the check box is checked
public ActionResult Index(bool showOnlyActive = true)
{
RecordList recordList = searchForRecordList(showOnlyActive);
return View("Index", recordList) ;
}
Does anyone have any Idea what I am missing?
I am still not sure why it works in firefox but not in Chrome and IE, but I found a solution that works for all.
I wrote an event for the click function of the link in jquery.
$("#lnkShowAll").click(function(event)
{
var link = $(this);
var target = link.attr("target");
if($.trim(target).length > 0)
{
window.open(link.attr("href"), target);
}
else
{
window.location = link.attr("href");
}
event.preventDefault();
});
And added a click function to trigger a click event of the link when the checkbox is checked/unchecked.
$("#chkShowAll").click(function(){
$("#lnkShowAll").click();
});
This ensures that the link is clicked whenever the checkbox is clicked on no matter what browser you are using.

twitter bootstrap dynamic carousel

I'd like to use bootstrap's carousel to dynamically scroll through content (for example, search results). So, I don't know how many pages of content there will be, and I don't want to fetch a subsequent page unless the user clicks on the next button.
I looked at this question: Carousel with dynamic content, but I don't think the answer applies because it appears to suggest loading all content (images in that case) from a DB server side and returns everything as static content.
My best guess is to intercept the click event on the button press, make the ajax call for the next page of search results, dynamically update the page when the ajax call returns, then generate a slide event for the carousel. But none of this is really discussed or documented on the bootstrap pages. Any ideas welcome.
If you (or anyone else) is still looking for a solution on this, I will share the solution I discovered for loading content via AJAX into the Bootstrap Carousel..
The solution turned out to be a little tricky since there is no way to easily determine the current slide of the carousel. With some data attributes I was able to handle the .slid event (as you suggested) and then load content from another url using jQuery $.load()..
$('#myCarousel').carousel({
interval:false // remove interval for manual sliding
});
// when the carousel slides, load the ajax content
$('#myCarousel').on('slid', function (e) {
// get index of currently active item
var idx = $('#myCarousel .item.active').index();
var url = $('.item.active').data('url');
// ajax load from data-url
$('.item').html("wait...");
$('.item').load(url,function(result){
$('#myCarousel').carousel(idx);
});
});
// load first slide
$('[data-slide-number=0]').load($('[data-slide-number=0]').data('url'),function(result){
$('#myCarousel').carousel(0);
});
Demo on Bootply
I combined #Zim's answer with Bootstrap 4. I hope it will help someone.
First, load just the path of the images:
<div id="carousel" class="carousel slide" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item" data-url="/image/1.png"></div>
<div class="carousel-item" data-url="/image/2.png"></div>
<div class="carousel-item" data-url="/image/3.png"></div>
</div>
</div>
Then in JavaScript:
$('document').ready(function () {
const loadCarouselImage = function ($el) {
let url = $el.data('url');
$el.html(function () {
let $img = $('<img />', {
'src': url
});
$img.addClass('d-block w-100');
return $img;
});
);
const init = function () {
let $firstCarousel = $('#carousel .carousel-item:first');
loadCarouselImage($firstCarousel);
$firstCarousel.addClass('active');
$('#productsCarousel').carousel({
interval: 5000
});
};
$('#carousel').on('slid.bs.carousel', function () {
loadCarouselImage($('#carousel .carousel-item.active'));
});
init();
});

dynamically add jquery tab in view

I am very new to MVC and jQuery and I have a problem adding a new tab to a jQuery tab panel.
I have a ASP.NET MVC3 View that contains two partial views. The first one is a search form and the second one displays the search results.
Now I need to put the search results in a tab of a tab panel. At a later point in this project it should work like this: The user searches for some keywords, and for each new search a new tab is added to the tab panel. This way it should be possible for the user to switch to a previous search. But I am not this far yet.
What I tried first was to add a static tab panel to the page with a single tab that contains the search results. This was rather easy and I had no problems. What I tried to do next, was to add a new tab with static content ("Hello World") to the tab panel each time the user clicks the submit button of the search form. But this doesn't really work:
I can see that the new tab is added to the tab panel. But only for < 1 sec. The new tab disappears as soon as the search results are rendered. It seems like rendering the partial view overwrites the changes made by jQuery/JavaScript.
This is the view (_SearchInput is the partial view for the search form, _SearchResults is the partial view used to display search results):
<div class="roundedBorder">
#Html.Partial("_SearchInput")
</div>
<div id="tabs" style="margin-top:7px;">
<ul>
<li>Test 1</li>
</ul>
<div id="contentcontainer">
<div id="fragment-1">#Html.Partial("_SearchResults")</div>
</div>
</div>
In _SearchInput I add the tabs when the document is ready and call searchClick when the submit button of the form is clicked:
<script>
$(document).ready(function () {
/* show tabs */
$('#tabs').tabs();
});
function searchClick() {
var keyword = $("#searchTextInput").val().trim();
if (keyword == null || keyword == "") {
return false;
}
var title = keyword.substring(0, 10);
$('#contentcontainer').append("<div id='fragment-2'>hello world</div>");
$('#tabs').tabs("add", "#fragment-2", title);
}
</script>
How are you submitting the form? If your not posting an ajaxy type of result this would be expected as your page will be refreshing on form submit.
Rather, than submit the form, submit the form with jquery and in your success callback perform your post form submission tasks.
EG:
$('form').submit(function(evt) {
evt.preventDefault();
$.ajax({
type: "POST",
url: "formsubmiturl",
data: dataposted,
success: function() {
// add jquery tab stuff here
}
});

Resources