ng-if condition always fails - html

I'm using AngularJS
<div ng-repeat="l in kites">
<a ng-click="findit(l.green.num)">color</a>
<span ng-if="c_{{l.green.num}} == 'y'>kites is </span>
</div>
In my controller I have
$scope.cnt=[];
$scope.findit = function(c){
$scope.cnt.push(c);
angular.forEach($scope.cnt, function(value, key){
$scope['c_'+value] = 'y' ;
})
}
My problem is, I'm not getting the span value even the conditions falls true..
means while l.green.num is 5 , c_5 ='y'. But it is not accepted in the if condition. Please help me.

Below is your solution:
var $scope;
var app = angular.module('miniapp', []);
function Ctrl($scope) {
$scope.kites = [{
'green':{
'num':1
}
}]
$scope.cnt = [];
$scope.findit = function(c) {
$scope.cnt.push(c);
angular.forEach($scope.cnt, function(value, key) {
$scope['c_' + value] = 'y';
})
}
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="miniapp" ng-controller="Ctrl">
<div ng-repeat="l in kites">
<a ng-click="findit(l.green.num)">color</a>
<span ng-show="{{'c_'+l.green.num}} == 'y'">kites is </span>
</div>
</div>

I'm not sure you can use brackets in ng-if conditions. This won't interpolate the value before evaluation.
What you could do is adding a "selected" value to your kite when clicked.
Example :
Controller
$scope.findit = function(c){
c.selected = true;
}
View
<div ng-repeat="l in kites">
<a ng-click="findit(l.green)">color</a>
<span ng-if="l.green.selected">kites is </span>
</div>

Related

Splitting up results of knockout data into 2 columns

Was curious if there was an easy way to split up the following code into 2 columns via Knockout and HTML. I know how to do it in the CSS but really it's just to split results 1-5 and 6-9. Here's my code. Screenshot attached as well. Thank you
<div class="item summary">
<h3> <?=l(479)?> </h3>
<div data-bind="foreach:$data.summary">
<div>
<span data-bind="text:$data.sequence + '.'"></span>
<span data-bind="text:$data.label + ':'"></span>
<span data-bind="text:$data.value"></span>
</div>
</div>
</div>
If the length isn't going to change you can duplicate the markup for each block and add a slice(). It's not the most elegant but it's probably the easiest.
<!-- ko if: summary && summary.length > 0 -->
<div data-bind="foreach: $data.summary.slice(0,5)">
...
<div data-bind="foreach: $data.summary.slice(5)">
...
<!-- /ko -->
If you want something a little more dynamic you can create a computed function that splits your array into multiple pieces and use a nested foreach instead:
function viewModel(){
var self = this;
this.summary = [
new Summary(1),
new Summary(2),
new Summary(3),
new Summary(4),
new Summary(5),
];
this.summaryBlocks = ko.computed(function(){
if(self.summary && self.summary.length > 0){
var size = self.summary.length / 2;
return [
self.summary.slice(0,size),
self.summary.slice(size)
];
}else{
return [];
}
});
}
function Summary(val){
this.sequence = 'sequence';
this.label = 'label';
this.value = val;
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="item summary">
<h3> <?=l(479)?> </h3>
<div data-bind="foreach: summaryBlocks">
<div style="display:inline-block; vertical-align:top;" data-bind="foreach:$data">
<div>
<span data-bind="text:$data.sequence + '.'"></span>
<span data-bind="text:$data.label + ':'"></span>
<span data-bind="text:$data.value"></span>
</div>
</div>
</div>
</div>
EDIT: Another snippet for dealing with a variable number of columns
function viewModel() {
var self = this;
this.columns = ko.observable(1);
this.summary = [new Summary(1), new Summary(2), new Summary(3), new Summary(4), new Summary(5), new Summary(6), new Summary(7), new Summary(8), new Summary(9)];
this.summaryBlocks = ko.pureComputed(function() {
var result = [];
for (var i = 0; i < self.columns(); i++) result.push([]);
if (self.summary && self.summary.length > 0) {
for (var i = 0; i < self.summary.length; i++) {
var col = i % self.columns();
result[col].push(self.summary[i]);
}
}
return result;
});
}
function Summary(val) {
this.sequence = 'sequence';
this.label = 'label';
this.value = val;
}
ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
columns: <span data-bind="text: columns"></span>
<br/><input type="range" min=1 max=5 data-bind="value: columns" />
<div class="item summary">
<div data-bind="foreach: summaryBlocks">
<div style="display:inline-block; vertical-align:top;" data-bind="foreach:$data">
<div style="border: 1px dashed blue;">
<span data-bind="text:'item ' + value"></span>
</div>
</div>
</div>
</div>

Swipe to Reveal is not working

I have implemented a swipe to reveal Oracle JET component.
Below is my Js code
this.action = ko.observable("No action taken yet");
this.handleReady = function()
{
// register swipe to reveal for all new list items
$("#listview").find(".item-marker").each(function(index)
{
var item = $(this);
var id = item.prop("id");
var startOffcanvas = item.find(".oj-offcanvas-start").first();
var endOffcanvas = item.find(".oj-offcanvas-end").first();
// setup swipe actions
oj.SwipeToRevealUtils.setupSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.setupSwipeActions(endOffcanvas);
// make sure listener only registered once
endOffcanvas.off("ojdefaultaction");
endOffcanvas.on("ojdefaultaction", function()
{
self.handleDefaultAction(item);
});
});
};
this.handleDestroy = function()
{
// register swipe to reveal for all new list items
$("#listview").find(".item-marker").each(function(index)
{
var startOffcanvas = $(this).find(".oj-offcanvas-start").first();
var endOffcanvas = $(this).find(".oj-offcanvas-end").first();
oj.SwipeToRevealUtils.tearDownSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.tearDownSwipeActions(endOffcanvas);
});
};
this.handleMenuBeforeOpen = function(event, ui)
{
var target = event.originalEvent.target;
var context = $("#listview").ojListView("getContextByNode", target);
if (context != null)
{
self.currentItem = $("#"+context['key']);
}
else
{
self.currentItem = null;
}
};
this.handleMenuItemSelect = function(event, ui)
{
var id = ui.item.prop("id");
if (id == "read")
self.handleRead();
else if (id == "more1" || id == "more2")
self.handleMore();
else if (id == "tag")
self.handleFlag();
else if (id == "delete")
self.handleTrash();
};
this.closeToolbar = function(which, item)
{
var toolbarId = "#"+which+"_toolbar_"+item.prop("id");
var drawer = {"displayMode": "push", "selector": toolbarId};
oj.OffcanvasUtils.close(drawer);
};
this.handleAction = function(which, action, event)
{
if (event != null)
{
self.currentItem = $(event.target).closest(".item-marker");
// offcanvas won't be open for default action case
if (action != "default")
self.closeToolbar(which, self.currentItem);
}
if (self.currentItem != null)
self.action("Handle "+action+" action on: "+self.currentItem.prop("id"));
};
this.handleRead = function(data, event)
{
self.handleAction("first", "read", event);
};
this.handleMore = function(data, event)
{
self.handleAction("second", "more", event);
};
this.handleFlag = function(data, event)
{
self.handleAction("second", "Rejected", event);
};
this.handleTrash = function(data, event)
{
self.handleAction("second", "Accepted", event);
self.remove(self.currentItem);
};
this.handleDefaultAction = function(item)
{
self.currentItem = item;
self.handleAction("second", "default");
self.remove(item);
};
this.remove = function(item)
{
// unregister swipe to reveal for removed item
var startOffcanvas = item.find(".oj-offcanvas-start").first();
var endOffcanvas = item.find(".oj-offcanvas-end").first();
oj.SwipeToRevealUtils.tearDownSwipeActions(startOffcanvas);
oj.SwipeToRevealUtils.tearDownSwipeActions(endOffcanvas);
alert(JSON.stringify(self.allItems()));
alert(item.toString());
self.allItems.remove(function(current)
{
return (current.id == item.prop("id"));
});
};
}
return PeopleViewModel;
});
HTML code:
<ul id="listview"
data-bind="ojComponent: {component: 'ojListView',
data: listViewDataSource,
item: {template: 'peoplelist_template'},
selectionMode: 'single',
ready: handleReady,
destroy: handleDestroy,
optionChange: changeHandler,
rootAttributes: {style: 'width:100%;height:100vh;overflow:auto; margin-top: 5px'},
scrollPolicy: 'loadMoreOnScroll',
scrollPolicyOptions: {fetchSize: 10}}">
</ul>
<script id="peoplelist_template">
<div style="padding:0.8571rem">
<div class="oj-flex oj-flex-items-pad">
<div class="oj-flex-item oj-lg-4 oj-md-4">
<img alt="employee image" class="demo-circular demo-employee-photo" style="float:left;" data-bind="attr: {src: $parent.getPhoto($data['name'])}"/>
<h2 class="demo-employee-name" data-bind="text: $data['from']"></h2>
<div class="demo-employee-title" data-bind="text: $data['title']"></div>
<div class="demo-employee-dept" data-bind="text: $data['deptName']"></div>
</div>
<div style="line-height: 1.5em; height: 3em; overflow: hidden; text-overflow: ellipsis" class="oj-text-sm oj-text-secondary-color" data-bind="text: $data['content']"></div>
</div>
</div>
<div tabIndex="-1" data-bind="attr: {id: 'first_toolbar_'+empId}" class="oj-offcanvas-start" style="width:75px">
<div data-bind="click:$parent.handleRead">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item demo-library-icon-24 demo-icon-font-24"></div>
<div style="padding-top: 10px" class="oj-flex-item">Read</div>
</div>
</div>
</div>
</div>
</div>
<div tabIndex="-1" data-bind="attr: {id: 'second_toolbar_'+empId}" class="oj-offcanvas-end" style="width:225px">
<div class="oj-swipetoreveal-more" data-bind="click: $parent.handleMore">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-bars"></div>
<div style="padding-top: 10px" class="oj-flex-item">More</div>
</div>
</div>
</div>
</div>
<div style="background-color:#b81900" data-bind="click: $parent.handleFlag" class="oj-swipetoreveal-flag">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-times"></div>
<div style="padding-top: 10px" class="oj-flex-item">Reject</div>
</div>
</div>
</div>
</div>
<div style="background-color:#009638" data-bind="click: $parent.handleTrash" class="oj-swipetoreveal-alert oj-swipetoreveal-default">
<div class="oj-flex-bar" style="height:100%">
<div class="oj-flex-bar-center-absolute">
<div class="oj-flex oj-sm-flex-direction-column">
<div title=".demo-library-icon-24" role="img" class="oj-flex-item fa fa-check"></div>
<div style="padding-top: 10px" class="oj-flex-item">Approve</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</li>
</script>
Actual problem is the listItem is not getting removed while approving.(The Approve div is call Handletrash function).
I dont know where I went wrong ??could anyone help me to solve this issue??
There's a lot of code here, which makes it hard to understand what everything is intended to do, and harder to pinpoint what the problem might be. That's why it's best to make a Minimal, Complete, and Verifiable Example. Also, in the process of removing all the code that does not directly affect your problem, you may solve it yourself.
I notice in your code that you have a number of jQuery calls. That's a significant red flag. Your contract with Knockout is that you will manipulate your data model and Knockout will use it to control the DOM. If you "go behind Knockout's back" and manipulate the DOM yourself, you and Knockout are going to be stepping on each other's toes.
Knockout provides two ways for you to customize how it manipulates the DOM: animated transitions and custom bindings. "Swipe to reveal" sounds like a transition to me, but looking at your code, it appears there's a whole lifecycle involved, so I think you need to make a custom binding handler.
All of your DOM-manipulating code should be inside the binding handler, and all of it should be restricted to the element of the binding handler. There should be no document-wide selectors.

Filter json file with tickboxes in Angular

I am trying to filter results from my JSON file so the user can click on ladies or mens 'styles', but some products have both a ladies and mens styles, so how would I be able to show the results for 'both' without having three tick boxes? I know I cannot have duplicate names in my JSON, but have done this just as an example for now. Any help would be appreciated. I have put my code here:
http://plnkr.co/edit/fXOZHqo48ntvsdJA875y?p=preview
<div ng-controller="myCtrl">
<div ng-repeat="(prop, ignoredValue) in { 'category': true, 'cut': true }" ng-init="filter[prop]={}">
<b>{{prop | capitalizeFirst}}:</b><br />
<span class="quarter" ng-repeat="opt in getOptionsFor(prop)">
<b><input type="checkbox" ng-model="filter[prop][opt]" /> {{opt}}</b>
</span>
<hr />
</div>
<div ng-repeat="w in filtered=(products | filter:filterByProperties)">
{{w.name}} ({{w.category}})
</div>
<hr />
Number of results: {{filtered.length}}
</div>
You need to make couple of changes in your json.
Whenever there is cut has one value then it would be string & whenever there is more than one value then you could maintain an array
like "cut": "ladies", "cut": "mens", & "cut": ["ladies","mens"]
You need to handle string and filter thing in your filterByProperties function
Markup
<span ng-show="!isArray(opt)" class="quarter" ng-repeat="opt in getOptionsFor(prop)">
<b><input type="checkbox" ng-model="filter[prop][opt]" /> {{opt}}</b>
</span>
Code
$scope.isArray = function(val) {
return angular.isArray(val)
}
$scope.filterByProperties = function(product) {
// Use this snippet for matching with AND
var matchesAND = true;
for (var prop in $scope.filter) {
if (noSubFilter($scope.filter[prop])) continue;
if (!$scope.isArray(product[prop])) { //if its not an array
if (!$scope.filter[prop][product[prop]]) {
matchesAND = false;
break;
}
} else {
//if its an array
for (var i = 0; i < product[prop].length; i++) {
var anyPropMatch = false;
if ($scope.filter[prop][product[prop][i]]) {
anyPropMatch = true;
break;
}
}
if (!anyPropMatch) {
matchesAND = false;
break;
}
}
}
return matchesAND;
};
Working Plunkr

Angular - toggle class, text, and scroll in controller using ngclick

I have been rewriting some Jquery tasks that I had previously written and want them to now work in my AngularJs App.
I am able to toggle the glyphicons, but how can I change the text and scroll feature as well?
This is my code:
HTML
<body ng-app="toggleApp" ng-controller="toggleCtrl as tc">
<a ng-click="tc.toggle('glyph'); tc.toggle('text')" class="lead p-color learn-button togglebtn shake shake-rotate">
<small>
<span id="toggleGlyph" ng-class="tc.iconGlyph ? 'glyphicon glyphicon-minus' : 'glyphicon glyphicon-plus'">
</span> <span ng-class="tc.textDesc ? 'Hide' : 'Learn More'">Learn More</span>
</small>
</a>
</body>
Main Javascript
var app = angular.module('app', ['ui.bootstrap', 'ngRoute', 'ngAnimate']);
app.config(function($interpolateProvider, $routeProvider) {
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
$routeProvider
.when('/', {
templateUrl : 'pages/LandingPage.html',
controller : 'LandingCtrl'
})
Controller Javascript
app.controller('toggleCtrl', function () {
this.toggle = function (property) {
this.iconGlyph = (property === 'glyph') ? !this.iconGlyph : this.iconGlyph;
this.textDesc = (property === 'text') ? !this.textDesc : this.textDesc;
}
});
Previous Jquery
$(function () {
$('a.togglebtn').click(function () {
$("#toggleGlyph").toggleClass("glyphicon-minus glyphicon-plus");
$('#toggleText').text($('#toggleText').text() === "Learn More" ? "Hide" : "Learn More");
$('#myContent').stop().slideToggle(500);
$('html,body').animate({ scrollTop: $('#myContent').offset().top - 200 }, 800);
return false;
});
});
http://jsfiddle.net/amptwig91/7jf5sdnv/
check this snippet
var app = angular.module("app", []);
app.controller('toggleCtrl', function() {
var _parent = this;
this.toggle = function() {
_parent.isToggled = !_parent.isToggled;
setText();
}
function setText() {
if (_parent.isToggled) {
_parent.text = 'Hide';
} else {
_parent.text = 'Learn More';
}
}
this.isToggled = false;
this.text = 'Learn More';
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<body ng-app="app" ng-controller="toggleCtrl as _">
<i class="fa" ng-class="{'fa-plus' : !_.isToggled , 'fa-minus' : _.isToggled }"></i> {{_.text}}
<body>
Since I am using UI-Bootstrap. This is how I ended up solving it!
<a class="lead p-color learn-button togglebtn shake shake-rotate" data-ng-init="isCollapsed1 = true" data-ng-click="isCollapsed1 = !isCollapsed1">
<small>
<div ng-show="isCollapsed1">
<span class="glyphicon glyphicon-plus" ></span> Learn More
</div>
<div ng-hide="isCollapsed1">
<span class="glyphicon glyphicon-minus"></span> Hide
</div>
</small>
</a>

Calculate a total from autocomplete suggestion.data

I'm trying to write a small Jquery program with an autocomplete searchform. I would like the user to be able to add items from the autocomplete form to a sort of shopping list. I have difficulties finding a way to calculate and update the total price of all added products, I tried to store the prices, which are in suggestion.data and tot add it recusively to a total as in
total = total + suggestion.data, but this seems not to be the way. Could someone help me to produce and display this total? My jQuery code is as follows:
var Price = {};
var Name = {};
var Totaal = {};
$(function () {
var currencies = [
{value:'TEXT-STRING',data:'5.50)'},
{value:'TEXT-STRING2',data:'3.10)'},
];
$('#autocomplete').autocomplete({
lookup: currencies,
onSelect: function (suggestion) {
Price.fff = suggestion.data;
Name.fff = suggestion.value;
},
});
});
function addListItem() {
var write2 = Price.fff;
var write = $('#autocomplete').val();
var list = $('#itemList');
var item = $('<li><span class="list">' + write + '</span><button
class="delete">X</button></li>');
var autocomplete = $("#autocomplete");
if (write.length === 0 || write.length > 88) {
return false;
}
if (write == Name.fff) {
list.append(item);
list2.append(item2);
$(autocomplete).val('');
}
$(autocomplete).val('');
}
function deleteItem() {
$(this).parent().remove();
}
$(function () {
var add = $('#addItem');
var autocomplete = $('#autocomplete');
var list = $('#itemList');
add.on('click', addListItem);
list.on('click', '.delete', deleteItem);
autocomplete.on('keypress', function (e) {
if (e.which == 13) {
addListItem();
}
}
And my HTML looks like:
<body>
<div id="box-1"> </div>
<div id="box-2"> </div>
<div id="page">
<h1>Shop</h1>
</div>
<div id="main">
<div id="top">
<div id="form">
<div id="searchfield">
<input type="text" id="autocomplete" name="currency" class="biginput" placeholder="ADD ITEMS BELOW">
<input type="submit" id="addItem" value="+">
</div>
<div class="line"> </div>
</div>
<div id="bottom">
<div class="items">
<ul id="itemList">
</ul>
</div>
</div>
Keep added item in array with prices, so you can recalculate total at any time. Don't forget to remove it from array when removing from the list.
Don't keep data in DOM, use DOM only to display info that is in your model.