Angular Bootstrap UI Modal - Next/Previous - angularjs

I'm relatively new to Angular, and am using it to filter a large list of products, and then that list of products has the ability to be opened in a modal where additional details are displayed.
I've seen a working example of a next/previous modal that's NOT using bootstrap UI, but have yet to see one that IS using bootstrap UI.
Here's a Plunker with a simplified working list and modal via bootstrap UI but I've been going crazy trying to figure out how to show the next/previous modal from inside the opened modal?
http://plnkr.co/edit/mRxzn8crtkaKCL8SZlQB?p=preview
var app = angular.module('sortApp', ['ui.bootstrap']);
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, feature) {
$scope.feature = feature;
$scope.ok = function (feature) {
$modalInstance.close($scope.feature);
};
});
angular.module('sortApp').controller('mainController', function ($scope, $modal, $log) {
// MODAL WINDOW
$scope.open = function (_feature) {
var modalInstance = $modal.open({
controller: "ModalInstanceCtrl",
templateUrl: 'myModalContent.html',
keyboard: true,
resolve: {
feature: function () {
return _feature;
}
}
});
//No CLUE WHAT TO DO HERE!?
$scope.showNext = function (_feature, index) {
if ((index + 1) > ($scope.allfeatures.length - 1)) {
return;
}
else {
turtle.show = false;
$scope.allfeatures[index + 1].show = true;
}
};
};
// create the list of features
$scope.allfeatures = [
//Website Widgets
{ index: 0, ID: 1, image: 'img/upload-tools.png', name: 'Upload Tools', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Attendees can upload credentials, student verification letters, professional licenses and other documentation required to validate their registration status.' },
{ index: 1, ID: 1, image: 'img/translation.png', name: 'Website Translation', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Microsoft Translator is used to translate your registration and housing websites with the click of one button.' },
{ index: 2, ID: 1, image: 'img/fundraising.png', name: 'Fundraising Motivator', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Encourage your attendees to help you reach fundraising goals with visually appealing dynamically populated graphics.' },
{ index: 3, ID: 1, image: 'img/analytics.png', name: 'Google Analytics', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: "<h2>Know your audience</h2> <p>Google Analytics helps you analyze visitor traffic and paint a complete picture of your audience and their needs, wherever they are along the path to purchase. Giving you an edge on what your visitors need and want.</p> <h2>Trace the customer path</h2><p>Knowing where a customer is on your site, and how they got there is a critical part of finding out who they are. Tools like Traffic Sources and Visitor Flow help you track the routes people take to reach you, as well as the devices they use to get there. Armed with this valuable information an ideal user experience can be created for them.</P> <h2>Analyze important trends</h2> Utilize a tool like In-Page Analytics which lets you make a visual assessment of how visitors interact with your pages. Learn what they're looking for and what they like, then tailor all of your marketing activities for maximum impact." }
];
});
and the HTML
<body ng-app="sortApp" ng-controller="mainController">
<br>
<div class="container">
<ul class="list-group">
<li class="list-group-item" ng-repeat="feature in allfeatures">
<a ng-click="open(feature)">
<div class="card-content">
{{ feature.name }}
</div>
</a>
</li>
</ul>
</div>
<!--MODAL WINDOW-->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>{{ feature.name }}</h3>
</div>
<div class="modal-body">
<h5>{{ feature.category }}</h5>
<h5>{{ feature.type }}</h5>
</p>
</div>
<div class="modal-footer">
<div class="row">
<div class="col-sm-6 text-left">
<a class="previous btn btn-default btn-lg" ng-click="showPrev(t, $index)"><i class="fa fa-arrow-left"></i> Previous</a>
</div>
<div class="col-sm-6 text-right">
<a class="next btn btn-default btn-lg" ng-click="showNext(t, $index)">Next <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</script>
</body>

Check this out: http://plnkr.co/edit/COFgAJ1UpZlHLEe2VOoq?p=preview
Your showPrev and showNext functions are supposed to go inside your ModalInstanceController:
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, feature) {
$scope.feature = feature;
$scope.showNext = function (feature, index) {
$modalInstance.close("next");
};
$scope.showPrev = function(feature, index) {
$modalInstance.close("prev");
};
});
The logic for this part is nearly identical to the other example, except for what you do in each case:
angular.module('sortApp').controller('mainController', function ($scope, $modal, $log) {
// MODAL WINDOW
// create the list of features
$scope.allfeatures = [
//Website Widgets
{ index: 0, ID: 1, image: 'img/upload-tools.png', name: 'Upload Tools', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Attendees can upload credentials, student verification letters, professional licenses and other documentation required to validate their registration status.' },
{ index: 1, ID: 1, image: 'img/translation.png', name: 'Website Translation', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Microsoft Translator is used to translate your registration and housing websites with the click of one button.' },
{ index: 2, ID: 1, image: 'img/fundraising.png', name: 'Fundraising Motivator', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: 'Encourage your attendees to help you reach fundraising goals with visually appealing dynamically populated graphics.' },
{ index: 3, ID: 1, image: 'img/analytics.png', name: 'Google Analytics', type: 'Website Widgets', category: 'Registration, Exhibitor, Housing', description: "<h2>Know your audience</h2> <p>Google Analytics helps you analyze visitor traffic and paint a complete picture of your audience and their needs, wherever they are along the path to purchase. Giving you an edge on what your visitors need and want.</p> <h2>Trace the customer path</h2><p>Knowing where a customer is on your site, and how they got there is a critical part of finding out who they are. Tools like Traffic Sources and Visitor Flow help you track the routes people take to reach you, as well as the devices they use to get there. Armed with this valuable information an ideal user experience can be created for them.</P> <h2>Analyze important trends</h2> Utilize a tool like In-Page Analytics which lets you make a visual assessment of how visitors interact with your pages. Learn what they're looking for and what they like, then tailor all of your marketing activities for maximum impact." }
];
$scope.open = function (_feature, index) {
var modalInstance = $modal.open({
controller: "ModalInstanceCtrl",
templateUrl: 'myModalContent.html',
keyboard: true,
resolve: {
feature: function () {
return _feature;
}
}
});
modalInstance.result.then(function(result) {
if (result == "next") {
if(index +1 < $scope.allfeatures.length) {
$scope.open($scope.allfeatures[index+1], index+1);
}
}
else {
if(index -1 >= 0) {
$scope.open($scope.allfeatures[index-1], index-1);
}
}
});
};

Related

Using Semantic UI Search with CakePHP 3

I'm not sure what I'm doing wrong exactly but I've been on this for hours, when it's supposed to be relatively straightforward. Here's my html;
<div class="ui search focus">
<div class="ui left icon input">
<input class="prompt" type="text" placeholder="Search GitHub" autocomplete="off">
<i class="github icon"></i>
</div>
<div class="results"></div>
</div>
And here's my script
$(document).ready(function () {
$('.ui.search')
.search({
apiSettings: {
url: '//api.github.com/search/repositories?q={query}'
},
fields: {
results : 'items',
title : 'name',
url : 'html_url'
},
minCharacters : 3
});
});
This is exactly from the examples page: https://semantic-ui.com/modules/search.html#/examples
When I try to load local data in the form of
var content = [
{ title: 'Andorra' },
{ title: 'United Arab Emirates' },
{ title: 'Afghanistan' },
{ title: 'Antigua' },
{ title: 'Anguilla' },
// etc
];
$('.ui.search')
.search({
source: content
});
It works, no problems, however loading external content like in the first snippet shows No results found and when I check the network tab in Network in Browser Dev tool, I see a 307 Internal Redirect on the request and another with a 200 Ok request which apparently gets the data from Github. Obviously I'm missing something here and will really appreciate some guidelines please. Thanks
you can try this using Url helper
url: "<?= $this->Url->build('https://api.github.com/search/repositories?q={query}', true); ?>"

angular js ng-class shows expression as class instead of processing it

I'm trying to make highlighted menu items by using angular js. I've read this question and tried implementing the anwser, but instead of angular evaluating the expression, it just shows it as the class name. I don't know what's going on.
I have the menu items listed as JSON, and the iterate trough it with ng-repeat. Once the list items are created, I want the angular to add a class of 'active', if the location url is the same as the link.href attribute of a menu item (it's a json attribute, not the html one).
Here's the relevant html:
<div class="header" ng-controller="NavbarController">
<ul>
<li ng-repeat="link in menu" ng-class="{ active: isActive({{ link.href }}) }"><a ng-href="{{ link.href }}">{{ link.item }}</a>
</li>
</ul>
</div>
and my controller:
.controller('NavbarController', function ($scope, $location) {
// navbar links
$scope.menu = [
{
item: 'PTC-Testers',
href: '#/PTC-Testers'
},
{
item: 'articles',
href: '#/articles'
},
{
item: 'PTC sites',
href: '#/sites'
},
{
item: 'account reviews',
href: '#/account_reviews'
},
{
item: 'forum',
href: '#/forum'
},
{
item: 'contact us',
href: '#/contact'
},
{
item: 'login',
href: '#/login'
}
]; // end $scope.menu
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
});
This is the navbar part of a bigger project, and I tried only inserting the relevant code. If you need further info to understand the question properly, please let me know.
It should be ng-class="{'active' : isActive(link.href)}"
You didn't end the curly brace in ng-class and its better to put class name inside quotes

Angular Grouping Directive starting point

I'am trying to create a grouping and filtering mechanism with several predefined filters. I have a collection of undefined rules and some predefined grouping actions, for example "relativeDate" (today, tomorrow, yesterday, this week, ...), "boolean" or . The set of actions should be expandable.
I've managed to get this working in a controller. But I want to outsource this into a directive to get this working with other object collections. The Problem is: I need to specify the template of the list dynamically.
Imagine the following collections:
$scope.memosReceived = [
{ id: 1, from: 'Henry Ford', title: 'Want your Model T?', received: '2015-05-04T12:30:00', read: true },
{ id: 2, from: 'Oliver Newton', title: 'Look at this!', received: '2015-06-15T08:00:00', read: true }
...
];
$scope.memosSent = [
{ id: 1, to: 'Henry Ford', title: 'That is an old car', sent: '2015-05-04T12:35:21', read: true },
{ id: 2, to: 'Oliver Newton', title: 'Stop Spam', sent: '2015-06-15T08:01:47', read: false }
...
];
Now the markup should be like the following:
<div ng-controller="controller">
<h2>Received</h2>
<grouped-list ng-model="memosReceived" item-var="received" grouping-options="groupingReceived">
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
</grouped-list>
<h2>Sent</h2>
<grouped-list ng-model="memosSent" item-var="sent" grouping-options="groupingSent">
<h2>{{ sent.title }} <sub>to {{ sent.to }}</h2>
</grouped-list>
</div>
Options could be like:
$scope.groupingReceived = [
{ modelKey: 'received', action: 'relativeDate', options: { [.. passed to grouping action, like value->name mapping ..] },
{ modelKey: 'read', action: 'boolean', options: { [...] } }];
$scope.groupingSent = [
{ modelKey: 'sent', action: 'relativeDate', options: { [.. passed to grouping action, like value->name mapping ..] },
{ modelKey: 'read', action: 'boolean', options: { [...] } }];
The rendered HTML should look like this "PseudoHtml":
<div ng-controller="controller">
<h2>Received</h2>
<div class="grouped-list">
<div class="filter-section">
<button ng-click="openFilters = !openFilters>Open Filters</button>
<div class="filter-options" ng-hide="!openFilters">
<h4>Group by</h4>
[selectbox given group actions] [selectbox sort ascending or descending]
<h4>Filter by</h4>
[build filters by similar to group actions given filter actions]
</div>
</div>
<div class="group">
<div class="group-header">
<h3>Yesterday</h3>
</div>
<ul class="group-list">
<li ng-repeat="received in ngModel | customFilters">
<!-- something like transclusion starts here -->
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
<!-- something like transclusion ends here -->
</li>
</ul>
</div>
<div class="group">
<div class="group-header">
<h3>Last Week</h3>
</div>
<ul class="group-list">
<li ng-repeat="received in ngModel | customFilters">
<!-- something like transclusion starts here -->
<h2>{{ received.title }} <sub>by {{ received.from }}</h2>
<!-- something like transclusion ends here -->
</li>
</ul>
</div>
</div>
<h2>Sent</h2>
<div class="grouped-list">
[... same like above ...]
</div>
</div>
I am really struggeling how to achieve this behavior, where to store the several parts of the logic (e.g. the grouping actions, the custom filters) and how to transclude this correctly.
Maybe someone can give me a good starting point for that.
You could create a custom filter and call it from the controller of your directive.
Inside of this filter you can decide which filter action should be triggered by passing parameters to the filter.
I would call it from the controller instead of the template because there you can easier chain your filters.
Please have a look at the demo below or in this jsfiddle.
During adding my code to SO I've detected a bug (not displaying the item) in my code with a newer AngularJS version. Not sure what it is but with 1.2.1 it's working.
I'll check this later. Seems like a scoping issue.
angular.module('demoApp', [])
.filter('aw-group', function($filter) {
var filterMethods = {
relativeDate: function(input, action) {
console.log('relative date called', input);
return input; // do the translation to relative date here
},
filterByNumber: function(input, action, options) {
// if you need mor parameters
return $filter('filter')(input, options.number);
},
otherFilter: {
}
};
return function(input, action, options) {
return filterMethods[action](input, action, options);
};
})
.directive('groupedList', function () {
return {
restrict: 'E',
scope: {
model: '=',
itemVar: '=',
filter: '='
},
transclude: true,
template: '<ul><li ng-repeat="item in filteredModel" ng-transclude>'+
'</li></ul>',
controller: function($scope, $filter) {
//console.log($scope.filter);
$scope.filteredModel = $filter('aw-group')($scope.model, 'filterByNumber', { number: 2 }); // passing action from $scope.filter.action as second parameter, third is an options object
}
};
})
.controller('mainController', function () {
this.data = [{
title: 'Test1',
from: 'tester1'
}, {
title: 'Test2',
from: 'tester1'
}, {
title: 'Test3',
from: 'tester1'
}, ];
this.groupingReceived = [{
modelKey: 'received',
action: 'relativeDate',
options: {},
modelKey: 'read',
action: 'boolean',
options: {}
}];
this.memosReceived = [{
id: 1,
from: 'Henry Ford',
title: 'Want your Model T?',
received: '2015-05-04T12:30:00',
read: true
}, {
id: 2,
from: 'Oliver Newton',
title: 'Look at this!',
received: '2015-06-15T08:00:00',
read: true
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<grouped-list model="ctrl.data" item-var="received" filter="ctrl.groupingReceived">
<h2>{{item.title}}<sub>{{item.from}}</sub></h2>
</grouped-list>
</div>

Bind a controller $scope to objects in service

I'm creating a multi-step wizard using angularjs. The steps in the wizard could potentially change by actions the user takes. I'm storing the steps in a navigation service. I want the navigation controller to respond to changes in the navigation steps (which occurs in the service). How do I do this? The below code does not work. Also I am using ui-router for the wizard steps, I'm wondering if I'm going about this the wrong way and the steps should be stored in the parent $scope rather than in a service. But examples I've found online suggest using a service.
Here's a jsfiddle I wrote to exhibit the behavior (http://jsfiddle.net/uLytj/16/)
Wizard Navigation Service:
angular.module("myApp").factory("wizardNavigationSvc", [function () {
var service = {};
var steps = []
var currentStep = {};
var currentStepIndex = 0;
return {
init: function() {
steps = [{ state: "wizard.options", display: "Options", isActive: true, isFirstStep: true },
{ state: "wizard.newmodel", icon: "glyphicon-plus", otherActions: ["Add Another Model"] },
{ state: "wizard.other", display: "Other" },
{ state: "wizard.customer", display: "Customer Info" },
{ state: "wizard.shipping", display: "Shipping Info" },
{ state: "wizard.review", display: "Review", isLastStep: true }];
currentStep = steps[0];
currentStepIndex = 0;
},
steps: steps,
currentStep: currentStep
};
}])
Wizard Navigation Controller:
myApp.controller('wizardNavigationCtrl', ['wizardNavigationSvc', '$scope', '$state', function (wizardNavigationSvc, $scope, $state) {
wizardNavigationSvc.init();
$scope.steps = wizardNavigationSvc.steps;
$scope.currentStep = wizardNavigationSvc.currentStep;
}])
Wizard Navigation view:
<div>
<ul class="nav nav-tabs wizard-tabs">
<li ng-repeat="step in steps"
ng-class="step.isActive ? 'active': ''">
<a ui-sref="{{step.state}}">
<span ng-if="step.icon" class="glyphicon" ng-class="step.icon"></span>
<span ng-if="!step.icon">{{step.display}}</span></a>
</li>
</ul>
</div>
looking at your jsfiddle, its not defined because the service is not returning anything
Ex: on one of the lines (in your service) you have:
steps: steps,
currentStep: currentStep,
these should be:
steps: function(){return steps),
currentStep: function(){return currentStep},
I do not understand why this worked or was needed. I had to put my scope variables inside the service within another object. Here is the fiddle: http://jsfiddle.net/uLytj/25/
And here is the applicable code:
myApp.service("wizardNavigationSvc", [function () {
var navigation = {
steps: [],
currentStep: {},
currentStepIndex: 0
};

Get selected object in angular select

I have a select that I'm populated and defaulting based on an outside value:
<select ng-model="course.instructor_id" ng-options="instructor.id as instructor.first_name for instructor in instructors"></select>
I think I need to keep the ng-model and options pretty close to this so it updates/defaults the course model correctly but I need to grab a property of the currently selected instructor object.
How do I get the currently selected object for this select?
I want to be able to show the picture of the currently selected instructor:
<img ng-src="selected_instructor.picture""/>
If you need to update the course model when a new instructor is selected, you can use
$scope.$watch
to watch for changes of the selected_instructor value.
Here is an example:
app.controller("instructorCtrl", function($scope) {
$scope.course = {
instructor_id: null
};
$scope.instructors = [{
id: 1,
firstName: "Stefano",
lastName: "Baroni",
imageUrl: "http://placehold.it/300x150"
}, {
id: 2,
firstName: "Elisa",
lastName: "Molinari",
imageUrl: "http://placehold.it/150x150"
}, {
id: 3,
firstName: "Stefano",
lastName: "De Gironcoli",
imageUrl: "http://placehold.it/200x150"
}]
$scope.$watch(
"selected_instructor",
function(newValue, oldValue) {
if (newValue === oldValue) {
return;
}
$scope.course.instructor_id = newValue.id;
}
)
})
html template:
<div ng-controller="instructorCtrl">
<img src="{{selected_instructor.imageUrl}}" />
<br/>
<select ng-model="selected_instructor" , ng-options="instructor.lastName for instructor in instructors">
<option value="">-- choose instructor--</option>
</select>
<br/><label>Currently selected instructor:</label>{{selected_instructor}}
<br/><label>Course:</label> {{ course }}
</div>
From what I've seen of your question, you are never setting the selected_instructor. Here's a Fiddle of my solution for you.
You were basically correct in your select tag and its ng-directives. Here's what I used for the HTML template:
<div ng-app="demoApp" ng-controller="demoCtrl">
<select ng-model="instructor" ng-options="teacher.lastName for teacher in instructors">
{{teacher.lastName}}
</select>
<img src="{{instructor.imageUrl}}" />
</div>
For the Angular base, I made a dummy app and controller as such:
angular.module('demoApp', []);
angular.module('demoApp')
.controller('demoCtrl', function ($scope) {
$scope.instructor = null;
$scope.instructors = {
{
firstName: "Scott",
lastName: "Bohle",
courses: ["CHEM110", "CHEM222"],
imageUrl: "http://placehold.it/300x150"
},
{
firstName: "Arial",
lastName: "Fenster",
courses: ["CHEM180"],
imageUrl: "http://placehold.it/150x150"
}
}
});
Also, bonus points to anyone who can tell what University I went to... (Hint, it's the best in Canada.)

Resources