I'm working on a simple application that replicated the behavior of a typical Android app. Right now there is no back end, I'm just using an object array in my controller. I have a basic list with a few items in it. When the list is clicked I want the array of the index as well as the details to be passed to a details page. This is the list.
<md-list-item class="md-3-line" ng-repeat="it in ec.events" ng-href="#/details">
<!--<md-button ng-click="ul.selectUser(it)" ng-class="{'selected' : it === ul.selected }">-->
<div class="md-list-item-text" layout="column" style="margin:5px 0;">
<!--<md-icon md-svg-icon="{{it.avatar}}" class="avatar"></md-icon>-->
<h3>{{it.description}}</h3>
<p><span style="color:black">Chapter: </span>{{it.chapter}}</p>
<p><span style="color:black">Date: </span>{{it.date}}</p>
<p><span style="color:black">Type: </span>{{it.type}}</p>
<p><span style="color:black">Days: </span>{{it.outing_days}}</p>
</div>
<md-divider></md-divider>
</md-list-item>
Right now I have and ng-href with a link to details but I need to pass the list info along to my new view. Here is the basics of the details page
<md-content flex layout-padding>
<p>{{description}}</p>
<p>{{chapter}}</p>
<p>{{type}}</p>
<p>{{date}}</p>
<md-content>
Both views share the same controller which contains a basic object array.
controller('AppCtrl',function($scope){
$scope.events = [
{description:'description1',date:'07/25/2016',type:'music',chapter:'Arizona'},
{description:'description2',date:'08/15/2016',type:'movie',chapter:'Texas'}
]
});
Here you go - CodePen
Pass $index to ng-click on the md-list-item.
Markup
<div ng-controller="AppCtrl" ng-cloak="" ng-app="MyApp">
<md-list-item class="md-3-line" ng-repeat="it in ec.events" ng-href="#/details" ng-click="showInfo($index)">
<div class="md-list-item-text" layout="column" style="margin:5px 0;">
<h3>{{it.description}}</h3>
<p><span style="color:black">Chapter: </span>{{it.chapter}}</p>
<p><span style="color:black">Date: </span>{{it.date}}</p>
<p><span style="color:black">Type: </span>{{it.type}}</p>
<p><span style="color:black">Days: </span>{{it.outing_days}}</p>
</div>
<md-divider></md-divider>
</md-list-item>
<br>
Click info:
<md-content flex layout-padding>
<p>{{info.description}}</p>
<p>{{info.chapter}}</p>
<p>{{info.type}}</p>
<p>{{info.date}}</p>
<md-content>
</div>
JS
angular.module('MyApp',['ngMaterial', 'ngMessages'])
.controller('AppCtrl', function($scope) {
$scope.ec = {};
$scope.ec.events = [
{description:'description1',date:'07/25/2016',type:'music',chapter:'Arizona'},
{description:'description2',date:'08/15/2016',type:'movie',chapter:'Texas'}
];
$scope.showInfo = function (index) {
$scope.info = $scope.ec.events[index];
}
});
Related
So I learning by building a portfolio SPA and I really want to use md-sidenav and so far it works but its showing up above my content and i want it to just push my content to the right when it's opened.
var app = angular.module('myApp', ['ngMaterial']);
app.controller('MyController', function($scope, $mdSidenav) {
$scope.openLeftMenu = function() {
$mdSidenav('left').toggle();
};
});
HTML
<div layout="row" ng-controller="MyController">
<!--MENU ICON AND FUNCTION -->
<md-button ng-click="openLeftMenu()">
<a><i class="material-icons medium">menu</i></a>
</md-button>
<md-sidenav md-component-id="left" class="md-sidenav-left md-whiteframe-z2" style="background-color: white;" >
<div class="container" style=" margin-top: 30px;
width: 90%;">
<img class="circle responsive-img ram " src="assets/avatar.png" style="margin-left: 13%">
<p style="font-weight:bold;
text-decoration:underline;color:#FF5E19;
letter-spacing:1pt;word-spacing:2pt;
font-size:18px;text-align:center;font-family:arial, helvetica, sans-serif;
line-height:1;">Ramin Joseph</p>
</div>
<div class="nav-wrapper">
<div class="col l12 s12 m12">
<ul style=" text-align:center;">
<li class="sbar">About</li>
<li class="sbar">Portfolio</li>
<li class="sbar">Shop</li>
<li class="sbar">Contact</li>
</ul>
</div>
</div>
</md-sidenav>
Use attribute md-is-locked-open on md-sidenav element.
However, then you'll have to change the logic how to open the sidenav. I would do it by binding md-is-locked-open to the model state property and then toggling it myself on click event:
<md-sidenav md-is-locked-open="isSideNavOpen">...</md-sidenav>
$scope.openLeftMenu = function() {
$scope.isSideNavOpen = !$scope.isSideNavOpen;
};
For new Angular Material version
Add mode="push" in your <md-sidenav>.
<md-sidenav mode="push">
</md-sidenav>
Refer this : Sidenave | Angular Material | Mode
I have a typical scenario where there is a list view and then there's a details view. You get to the details view by selecting a list item. There's data in the record that of course will inform the layout view of the details. What I see is that the subtemplate's helper function is being called too soon (during the list view rendering) to have the data for the list details . Furthermore, it's not being called when I click an item in the list. What am I doing wrong? I'm using Meteor 0.8.2 with jQM 1.4.3.
The HTML looks as follows:
<!-- details page -->
<div data-role="page" data-theme="q" id="listdetail">
<div data-role="header" data-position="fixed">
<a data-rel="back" href="#" data-transition="slideleft" class="baack fa fa-arrow-left"></a>
<div id="detailTitle" class="headertitle"></div>
</div>
<!-- /header -->
<div data-role="content" class="ma-req-detail" id="details">
{{> qDetails}}
</div>
</div>
<!-- /details page -->
<template name="qList">
{{#each items}}
{{>qListItems}}
{{/each}}
</template>
<template name="qListItems">
<li>
<div id="msg-container-{{requestId}}" class="processing-msg">
<i class="fa fa-2x fa-times-circle"></i>
<p class="msg-text-{{requestId}}">Action pending...</p>
</div>
<a id="requestId" href="#listdetail" data-name="{{additionalProperties}}" data-transition="slide" class="{{#if isProcessing}}ui-disabled{{/if}}">
<p class="requestor">{{additionalProperties.requestedForUid}}</p>
<p class="description">week of {{additionalProperties.workWeekOf}}</p>
<p class="reqdate">total hours: </p>
</a>
</li>
</template>
<template name="qDetails" >
<div role="main" class="q-details">
<div data-role="navbar" class="week-nav">
<ul>
{{#each days}}
{{>navElements}}
{{/each}}
</ul>
</div>
</div>
<div class="ma-buttons ui-fieldcontain ui-footer-fixed">
<div data-role="controlgroup" data-type="horizontal" class="" data-position-fixed="true" data-position="bottom">
<a data-mini="true" href="#" id="approve-request"
class="ui-btn ui-btn-c ui-corner-r ui-icon-check ui-btn-icon-left ma-btn approve">Approve</a>
</div>
</div>
</template>
<template name="navElements">
<li><a id="{{day}}Nav" href="#{{day}}">{{day}}<br><span class="digital-date">{{date}}</span></a></li>
</template>
The JS bits are:
Template.qDetails.rendered = function() {
$('#details').trigger('create');
};
Template.qDetails.helpers({
days: function() {
//TODO need a way to delay this function to call when details template is shown
var dt = Session.get("record").additionalProperties.workWeekOf;
var days = [];
var weekday = new Array(7);
weekday[0] = "SAT";
weekday[1] = "SUN";
weekday[2] = "MON";
weekday[3] = "TUE";
weekday[4] = "WED";
weekday[5] = "THU";
weekday[6] = "FRI";
var dtVal = dt.getDate();
for (var i = 0; i < 7; i++) {
var dayObj = {};
dayObj.date = dtVal + i;
dayObj.day = weekday[i];
days.push(dayObj);
}
return days;
}
});
Template.qDetails.record = function () {
return Session.get("record");
};
In the code above the "days" helper function is being called when the list page is shown which results in an error because it is trying to pull the "workWeekOf" date from a record that hasn't been selected yet. How can I get to this only call once a record has been selected?
This is slightly confusing, since there's nothing in the above that shows how yourqDetails template gets rendered in the first place. However, assuming it does, you can just use:
var dt = Session.get("record") ? Session.get("record").additionalProperties.workWeekOf : [default date]
[default date] could be anything sensible (like new Date()), but you need to return something to avoid the error being thrown. This is a pretty common but very easily solved problem in Meteor - you just need a suitable default for when your Session variable or Collection isn't yet ready.
Knockout newbie here. I have a page to display the customer info.
1st div should be displayed when customer info is present.
2nd div should be displayed when no customers are displayed
//1st Div
<div id="custInfoList" data-role="content"
data-bind="foreach: customers, visible : customers().length > 0">
<p data-bind="text: $data.info"></p>
</div>
//2nd Div
<div id="empty" data-role="content"
data-bind="visible: customers().length === 0 ">
<p>No Customer Information</p>
</div>
My model is like this:
var myModel = {
customers : ko.observableArray();
}
..and on page load I am adding this logic:
//On Page Load, call AJAX to populate the customers
//customers = {jsonData}
My page is using jQuery Mobile. My only problem is when the page is first displayed, the second div is displayed. When the Ajax json data returns, that's where it is hidden.
Is it possible to hide the second div while the ajax is still on loading and data has not yet returned?
UPDATE 2
On a related note, I tried the KO HTML template which I just read from the net
<!-- ko if: customers().length -->
<div id="custInfoList" data-role="content"
data-bind="foreach: customers, visible : customers().length > 0">
<p data-bind="text: $data.info"></p>
</div>
<!-- /ko -->
<div id="empty" data-role="content"
data-bind="if: customers().length === 0">
<p>No Customer Information</p>
</div>
but still unsuccessful. Any thoughts what is missing?
UPDATE 3
I tried updating what #shriek demonstrated in his fiddle http://jsfiddle.net/t0wgLt79/17/
<!-- ko if: customers() -->
<div id="custInfoList" data-role="content" data-bind="foreach: customers">
<p data-bind="text: $data"></p>
</div>
<!-- /ko -->
<div id="empty" data-role="content" data-bind="if: customers().length === 0" style="display: none;">
<p>No Customer Information</p>
</div>
<button data-bind="click:popCustomers">Populate</button>
My JS:
$.support.cors = true;
var test = {
customers: ko.observableArray(),
popCustomers: function () {
for (var i = 0; i < 3; i++) {
this.customers.push(i);
}
},
popByAjax: function () {
console.log("Calling JSON...");
$.getJSON("http://api.openweathermap.org/data/2.5/weather?id=2172797", function (data) {
console.log(data);
if (data.sys) {
this.customers.push(data.sys.country);
console.log("Loaded");
}
}.bind(this));
}
};
test.popByAjax();
ko.applyBindings(Object.create(test));
On initial load, the "AU" is displayed. Now change the weather?id=2172797 into weather?id=21727971 to make it invalid. I notice that the no customer information is not displayed.
As mentioned in the comment above, for Update 3 display:none is extraneous as it's already being taken care by if on the data-bind.
Second thing is the observableArray had to be emptied after receiving bad response because hiding/displaying is based on the comparison of that observableArray's length.
Code to fiddle with:-
http://jsfiddle.net/4hmqdsup/
you see the second div as well as the first div because the knockout applyBinding to your DOM elements, has not yet been occurred, which means the visible binding has not yet been evaluated, and therefore no element will be hidden accordingly, leaving it in its default state ( which is to be shown )
to overcome this behaviour, you only need to add a style="display: none;" to those elements you want them to be hidden by default, and then the visible binding will remove the display: none if it is evaluated to true.
so your code should be like this
//1st Div
<div id="custInfoList" data-role="content"
data-bind="foreach: customers, visible : customers().length > 0">
<p data-bind="text: $data.info"></p>
</div>
//2nd Div
<div id="empty" data-role="content"
data-bind="visible: customers().length === 0" style="display: none;">
<p>No Customer Information</p>
</div>
and btw, it does not matter whether you use visible or if binding, as the problem is not with the binding itself.
I guess you did wrongly in //customers = {jsonData}.
To update a ko.observable, you need to use customers(jsonData), not customers = jsonData.
ko.observable() returns a function, the setter is customers(newValue) and the getter is customers(), you need to use function call explicitly in both setter and getter.
I try to implement tinyscrollbar (tinyscrollbar.js) into jquery mobile with data-role=page. On the first page it works perfectly fine. but on the second page, the bar is missing. until i clicked on inspect element. I tried tinyscrollbar_update(), update(0), slideToggle().promise()... non works. They all give me different kind of errors.
looks like this
<div class="scrollbar1">
<div class="scrollbar" style="height: 200px;">
<div class="track" style="height: 200px;">
<div class="thumb" style="top: 0px; height: 32.6530612244898px;">
<div class="end"></div>
</div>
</div>
</div>
<div class="viewport">
<div class="overview">//text</div>
</div>
<div id="footerNavigation">
Back
Next
</div>
i copied the exact same code as above to my second page code:
<div id="theNextPage" data-role="page"><!--scrollbar code--></div>
and my javascript file:
$(document).ready(function() {
$('.scrollbar1').tinyscrollbar();
});
anybody has any idea how is that so? Any way to solve it?
I have found out away!
change the class into id.
class="scrollbar1" >> id="scrollbar1"
next page:
class="scrollbar2" >> id="scrollbar2"
$(document).ready(function() {
$('#scrollbar1').tinyscrollbar();
$('#scrollbar2').tinyscrollbar();
});
$(document).on("pageshow", "#theNextPage", function () {
var $scrollbar2 = $('#scrollbar2');
$scrollbar2.tinyscrollbar();
var scrollbar1 = $scrollbar2.data("plugin_tinyscrollbar")
$scrollbar2.update(0);
});
like this would be better
I have a list view inside a popup , when the user select a list element I want to change this element "li" background color , I have tried the following code it was working on jQuery mobile 1.3.2 but it didn't work when i upgraded my app to 1.4.0 , How can I change the background color of the list element when the user click on it ? please help me
<div data-role="page" id="index">
<div data-role="header" data-theme="b">Main</div>
<div data-role="content">
Show Popup
</div>
<div data-role="popup" id="MyPOPUP" data-position-to="window" data-corners="false" data- overlay-theme="a" data-dismissible="false">
<div data-role="header" data-theme="a">
<div style="text-align:center;float:center;padding-top:11px;">
<font size="6px" color="white">Countries</font>
</div>
</div>
<div id="scrollContent" class="content" data-role="content" style="background-color: white;">
<ul data-role="listview" id="countrieslist" style="margin: 0 !important;">
</ul>
</div>
</div>
</div>
Java script code
$('#index').on( 'pageinit',function(){
for(var i=1;i<=50;i++)
{
$('#countrieslist').append('<li id="'+i+'">'+''+'<font>'+Country+i+'</font>' +'</li>');
}
$('#countrieslist').listview('refresh');
});
$('#Btn1').on('touchstart', function(){
$(this).css({background: 'white'});
$(this).attr('href','#MyPOPUP');
});
$('#countrieslist').on('click','li', function() {
$(this).css({background: 'blue'});
selected_elem = $(this).attr('id');
alert('you selected' + selected_elem);
$('#MyPOPUP').popup('close');
});
You have a little typo in your loop that creates the countries, but other than that the code seems to work,
Here is a working DEMO
Because pageinit is deprecated n 1.4, I have used pagecreate; and in the for loop the word country after the font tag should be within the single quotes as it is not a variable. Also, in the li click, I reset all other countries to transparent background before setting the newly selected one:
$(document).on( 'pagecreate', '#index',function(){
for(var i=1;i<=50;i++) {
$('#countrieslist').append('<li id="'+i+'"><font>Country' + i +'</font></li>');
}
$('#countrieslist').listview('refresh');
$('#Btn1').on('click', function(){
$(this).css({background: 'white'});
$(this).attr('href','#MyPOPUP');
});
$('#countrieslist').on('click','li', function() {
$('#countrieslist li').css({background: 'transparent'});
$(this).css({background: 'blue'});
selected_elem = $(this).attr('id');
alert('you selected' + selected_elem);
$('#MyPOPUP').popup('close');
});
});