How do I create dynamic links in Knockout.? - javascript

I am trying to make a button clickable with a different URL depending on which outcomes are selected. At the moment my code shown below sends all links to http://example.com. I would like to make this change depending on which selections have been chosen by the user.
HTML
<div class="wrapper">
<div class="container">
<div class="row">
<div class="col-xs-12 text-right">
<button class="btn btn-default btn-corner" type="submit" data-bind="click: startOver, visible: queryData().id > 0">Start over</button>
</div>
</div>
</div>
<div class="container main">
<div class="row">
<div class="c12 text-center">
<h1 data-bind="text: queryData().text"></h1>
<h3 data-bind="text: queryData().subhead"></h3>
<h3><a data-bind="text: queryData().link, attr: {href: url}"></a></h3>
<div class="option-group" data-bind="foreach: queryData().answers">
<button class="btn btn-default btn-lg" type="submit" data-bind="click: $parent.goToTarget, text: text"></button>
</div>
<button class="btn btn-default" type="submit" data-bind="click: stepBack, visible: navHistory().length > 1">Previous Step</button>
<button class="btn btn-default" type="submit" data-bind="click: buyBook, visible: navHistory().length > 1">Buy the book</button>
</div>
</div>
</div>
<div class="push"></div>
</div>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"></script>
<script src="app.js?v=0.4.0"></script>
<script>
</script>
</body>
</html>
The Javascript is below:
var queries = [{
id: 0,
text: "Start?",
answers: [{
text: "Let's Start!",
target: 1
}]
}, {
id: 1,
text: "Which sectiondo you want",
answers: [{
text: "Foo",
target: 2
}, {
text: "Bar",
target: 3
}, {
text: "Foobar",
target: 4
}]
}, {
id: 2,
text: "Selection1",
link: "test2.com",
answers: []
}];
function QueryViewModel() {
var self = this;
self.url = ko.observable("https://example.com");
self.querySet = ko.observable();
self.currentStep = ko.observable();
self.queryData = ko.observable();
self.sfw = ko.observable();
self.navHistory = ko.observableArray();
// Operations
self.goToTarget = function(obj) {
self.navHistory.push(self.currentStep());
self.currentStep(obj.target);
self.queryData(self.querySet()[obj.target]);
}
self.startOver = function() {
self.navHistory.removeAll();
self.goToTarget({target: 0});
}
self.stepBack = function() {
var lastStep = self.navHistory().length > 1 ? self.navHistory.pop() : 0;
self.currentStep(lastStep);
self.queryData(self.querySet()[lastStep]);
}
this.buyBook = function() {
window.open("https://www.google.com", "_blank");
}
var paramsString = document.location.hash.substring(1);
var params = new Array();
if (paramsString) {
var paramValues = paramsString.split("&");
for (var i = 0; i < paramValues.length; i++) {
var paramValue = paramValues[i].split("=");
params[paramValue[0]] = paramValue[1];
}
}
params ? paramTarget = params['target'] : params = [];
self.sfw() ? self.querySet(queriesSFW) : self.querySet(queries);
if (paramTarget) {
self.navHistory.push(0);
self.currentStep(0);
self.goToTarget({target: paramTarget})
} else {
self.goToTarget({target: 0});
}
}
ko.applyBindings(new QueryViewModel());
At present the link2.com redirects to example.com I would like to replace the URL with the entry in the link2 attribute, so in this case test2.com but for other cases it would take the string shown for link and use that.

Related

random image from getElementById not working with multiple filters

I have a large array named quotes with values and I am trying to display a random image from that query based on a filter on the artic section, with a new random image in each on button click. Right now, this is working for the randomIR, randomMR, and randomFR, but my other subsequent filters like randomIS are not
const btn = document.querySelector("#btnSearch");
function GetValue() {
var quotes = [{
name: "Airplane",
artic: ["medialR", "Rair", "medialP", "medialL", "finalN",
img: "/img/airplane.png",
},
{
name: "Ring",
artic: ["initialR", "finalNG", "CVC", "syl1"],
img: "/img/ring.png",
},
{
name: "Soccer",
artic: ["initialS", "medialK", "finalR", "Rer", "syl2"],
img: "/img/soccer.png",
},
{
name: "Gas",
artic: ["initialG", "finalS", "CVC", "syl1"],
img: "/img/emojibase/gas.png",
},
{
name: "House",
artic: ["syl1", "finalS", "CVC"],
img: "/img/emojibase/house.png",
}
];
{
const quotesIR = quotes.filter(x => x.artic.includes("initialR"));
const quotesMR = quotes.filter(x => x.artic.includes("medialR"));
const quotesFR = quotes.filter(x => x.artic.includes("finalR"));
var randomIR = quotesIR[Math.floor(Math.random() * quotesIR.length)];
var randomMR = quotesMR[Math.floor(Math.random() * quotesMR.length)];
var randomFR = quotesFR[Math.floor(Math.random() * quotesFR.length)];
document.getElementById("IRtarget").src = randomIR.img;
document.getElementById("MRtarget").src = randomMR.img;
document.getElementById("FRtarget").src = randomFR.img;
};
{
const quotesIS = quotes.filter(x => x.artic.includes("initialS"));
const quotesMS = quotes.filter(x => x.artic.includes("medialS"));
const quotesFS = quotes.filter(x => x.artic.includes("finalS"));
var randomIS = quotesIS[Math.floor(Math.random() * quotesIS.length)];
var randomMS = quotesMS[Math.floor(Math.random() * quotesMS.length)];
var randomFS = quotesFS[Math.floor(Math.random() * quotesFS.length)];
document.getElementById("IStarget").src = randomIS.img;
document.getElementById("MStarget").src = randomMS.img;
document.getElementById("FStarget").src = randomFS.img;
};
btn.addEventListener("click", () => {
GetValue();
});
<div class="containerINITIAL" align="center">
<br>
<img id="IRtarget" src="/img/icons/rtest.png">
</div>
</div>
<div class="col-xs-4">
<div class="containerMEDIAL" align="center">
<br>
<img id="MRtarget" src="/img/icons/rtest.png">
<br>
<button id="btnSearch" align="center" onclick="GetValue();">New Words</button>
</div>
</div>
<div class="col-xs-4">
<div class="containerFINAL" align="center">
<br>
<img id="FRtarget" src="/img/icons/rtest.png">
</div>
<div class="containerINITIAL" align="center">
<br>
<img id="IStarget" src="/img/icons/stest.png">
</div>
</div>
<div class="col-xs-4">
<div class="containerMEDIAL" align="center">
<br>
<img id="MStarget" src="/img/icons/stest.png">
<br>
<button id="btnSearch" align="center" onclick="GetValue();">New Words</button>
</div>
</div>
<div class="col-xs-4">
<div class="containerFINAL" align="center">
<br>
<img id="FStarget" src="/img/icons/stest.png">
</div>
It was erroring for me because there was no "medialS" entry. This occurs because the code is trying to index an entry in an empty array. For safety's sake, you should test the results of your filters before trying to use them. E.g.
const quotesIR = quotes.filter(x => x.artic.includes("initialR"));
if (quotesIR.length) {
var randomIR = quotesIR[Math.floor(Math.random() * quotesIR.length)];
document.getElementById("IRtarget").src = randomIR.img;
}
I added a "medialS" entry to get the code working below, as well as a closing bracket after "finalN".
const btn = document.querySelector("#btnSearch");
function GetValue() {
var quotes = [{
name: "Airplane",
artic: ["medialR", "Rair", "medialP", "medialL", "finalN"],
img: "/img/airplane.png",
},
{
name: "Ring",
artic: ["initialR", "finalNG", "CVC", "syl1"],
img: "/img/ring.png",
},
{
name: "Soccer",
artic: ["initialS", "medialK", "finalR", "Rer", "syl2"],
img: "/img/soccer.png",
},
{
name: "Gas",
artic: ["initialG", "finalS", "CVC", "syl1"],
img: "/img/emojibase/gas.png",
},
{
name: "House",
artic: ["medialS","syl1", "finalS", "CVC"],
img: "/img/emojibase/house.png",
}
];
const quotesIR = quotes.filter(x => x.artic.includes("initialR"));
const quotesMR = quotes.filter(x => x.artic.includes("medialR"));
const quotesFR = quotes.filter(x => x.artic.includes("finalR"));
var randomIR = quotesIR[Math.floor(Math.random() * quotesIR.length)];
var randomMR = quotesMR[Math.floor(Math.random() * quotesMR.length)];
var randomFR = quotesFR[Math.floor(Math.random() * quotesFR.length)];
document.getElementById("IRtarget").src = randomIR.img;
document.getElementById("MRtarget").src = randomMR.img;
document.getElementById("FRtarget").src = randomFR.img;
const quotesIS = quotes.filter(x => x.artic.includes("initialS"));
const quotesMS = quotes.filter(x => x.artic.includes("medialS"));
const quotesFS = quotes.filter(x => x.artic.includes("finalS"));
var randomIS = quotesIS[Math.floor(Math.random() * quotesIS.length)];
var randomMS = quotesMS[Math.floor(Math.random() * quotesMS.length)];
var randomFS = quotesFS[Math.floor(Math.random() * quotesFS.length)];
document.getElementById("IStarget").src = randomIS.img;
document.getElementById("MStarget").src = randomMS.img;
document.getElementById("FStarget").src = randomFS.img;
};
<div class="containerINITIAL" align="center">
<br>
<img id="IRtarget" src="/img/icons/rtest.png">
</div>
</div>
<div class="col-xs-4">
<div class="containerMEDIAL" align="center">
<br>
<img id="MRtarget" src="/img/icons/rtest.png">
<br>
<button id="btnSearch" align="center" onclick="GetValue();">New Words</button>
</div>
</div>
<div class="col-xs-4">
<div class="containerFINAL" align="center">
<br>
<img id="FRtarget" src="/img/icons/rtest.png">
</div>
<div class="containerINITIAL" align="center">
<br>
<img id="IStarget" src="/img/icons/stest.png">
</div>
</div>
<div class="col-xs-4">
<div class="containerMEDIAL" align="center">
<br>
<img id="MStarget" src="/img/icons/stest.png">
<br>
<button id="btnSearch" align="center" onclick="GetValue();">New Words</button>
</div>
</div>
<div class="col-xs-4">
<div class="containerFINAL" align="center">
<br>
<img id="FStarget" src="/img/icons/stest.png">
</div>
From your notes and links, it looks like there's a different problem. When you have no 'R' images, you are getting an error because your function is still trying to set them. For example, document.getElementById("IRtarget") will return null on that page which causes an error when you try to set it's src property.
You could test for those elements before trying to set them:
if (document.getElementById("IRtarget")) {
const quotesIR = quotes.filter(x => x.artic.includes("initialR"));
var randomIR = quotesIR[Math.floor(Math.random() * quotesIR.length)];
document.getElementById("IRtarget").src = randomIR.img;
}

how to use pagination in angularjs?

So i am developing this app in which i want to apply pagination to list of templates.
template objects are stored in the list.
I am displaying thumbnails of templates on the page and i want to apply pagination for this page.
so far I have tried following solution but it didn't work.
list.html
<div class="container">
<div class="homepage-header">
<h2 class="homepage-title text-center wow fadeInDown animated" style="visibility: visible; animation-name: fadeInDown; -webkit-animation-name: fadeInDown;"> TEMPLATES </h2>
</div>
<div class="row">
<div class="col-md-6 col-sm-6" style="text-align: left">
<div class="form-inline">
<div class="form-group has-feedback has-clear">
<input type="text" class="form-control" ng-model="searchParam" ng-model-options="{ debounce: 400 }" placeholder="Search template ..."
/>
<a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" ng-click="searchParam = '';
retreivePageData(0);" ng-show="searchParam" style="pointer-events: auto; "></a>
</div>
</div>
</div>
<div class="col-md-6 col-sm-6" style="text-align: right; padding-right: 30px;">
<div class="form-inline">
<label>
<input type="radio" ng-model="selectedOption" value="All" ng-change="retrieveTemplates(selectedOption)"> All
</label>
<label>
<input type="radio" ng-model="selectedOption" value="Annotate" ng-change="retrieveTemplates(selectedOption)"> Annotate
</label>
<label>
<input type="radio" ng-model="selectedOption" value="Rapid" ng-change="retrieveTemplates(selectedOption)"> Component
</label>
</div>
</div>
</div>
<div class="homepage-ui-showcase-2-css row wow zoomIn animated" style="height: 402px;padding: 5px 0px; visibility: visible; animation-name: zoomIn; -webkit-animation-name: zoomIn;">
<div ng-repeat="(templateIndex, templateModel) in templatesList | filter:searchParam | limitTo: itemsPerPage">
<div class="active col-md-3 col-lg-3 col-sm-6 col-xs-12 mix design painting" style="display: inline-block;padding-top: 10px;"
ng-init="visible=false" ng-mouseover="visible=true" ng-mouseleave="visible=false">
<div class="portfolio-item shadow-effect-1 boxShadow" style="max-width: 250px;padding:0.3px;border:2px dotted #bebede;cursor: pointer">
<div class="mainBadge">
<kbd>{{templateModel.type}}</kbd>
</div>
<div ng-switch on="{{templateModel.type !== undefined && templateModel.type === 'Annotate'}}">
<div ng-switch-when="false" style="height: 130px;" ui-sref="/designer/:pageId({pageId:templateModel.id})" class="portfolio-img ">
<i style="opacity:0.4;padding-top:35px;padding-left:15px;margin-left: 30%;" class="fa fa-puzzle-piece fa-4x"></i>
</div>
<div ng-switch-when="true" style="height: 130px;" ui-sref="annotator/:annotatedTemplateId({annotatedTemplateId:templateModel.id})"
class="portfolio-img ">
<i style="opacity:0.4;padding-top:35px;padding-left:15px;margin-left: 30%;" class="fa fa-file-image-o fa-4x"></i>
</div>
</div>
<div class="portfolio-item-content" title="{{templateModel.name}}">
<h3 class="header" style="font-size: 13px;text-align: center;display:inline;">
{{templateModel.name}}
</h3>
<small class="pull-right" ng-show="visible" style="display: inline; padding-top: 4px">
<div ng-switch on="{{templateModel.type !== undefined && templateModel.type === 'Annotate'}}">
<div ng-switch-when="true" href="#" class="btn btn-xs btn-danger" title="Generate Communication"
ui-sref="generateCommunication({mode:'A',id: templateModel.id})"
ng-disabled="!templateModel.dynamic_entity"> <!--style="color:#9d9d9;"-->
<i class="fa fa-file-pdf-o"></i>
</div>
<div ng-switch-when="false" href="#" class="btn btn-xs btn-danger" title="Generate Communication"
ui-sref="generateCommunication({mode:'T',id: templateModel.id})"
ng-disabled="!templateModel.dynamic_entity"> <!--style="color:#9d9d9;"-->
<i class="fa fa-file-pdf-o"></i>
</div>
</div>
</small>
</div>
</div>
</div>
</div>
</div>
<div class="row " style="margin-top: 10px; padding-top:0px;">
<div class="pagination-div pull-right" style="">
<uib-pagination ng-model="currentPage" total-items="totalItems" max-size="maxSize" boundary-links="true">
</uib-pagination>
</div>
</div>
list.controller.js
'use strict';
angular.module('rapid').controller('HomeListController',
function($scope, $rootScope, $window, $uibModal, ServiceFactory, toaster, ReadFileService, AnnotationService, AnnotateService, DocumentService) {
$scope.templatesList = [];
$scope.filteredTemplates = [];
$scope.selectedOption = 'All';
$scope.annotateTemplateMeta = [];
$scope.rapidTemplateMeta = [];
$scope.init = function() {
$scope.selectedOption = "All";
//$scope.options = [{'label':'All', 'value':'All'}, {'label':'Annotate', 'value':'Annotate'}, {'label':'Component', 'value':'Component'}];
$scope.retrieveTemplates('All');
$scope.currentPage = 1;
};
$scope.retrieveTemplates = function(selectedOption) {
$scope.templatesList = [];
if (selectedOption === 'Annotate') {
$scope.fetchAnnotationTemplates(selectedOption);
} else if (selectedOption === 'Rapid') {
$scope.fetchRapidTemplates(selectedOption);
} else {
$scope.fetchAnnotationTemplates(selectedOption);
}
};
$scope.fetchAnnotationTemplates = function(selectedOption) {
AnnotateService.get().$promise.then(function(result) {
$scope.annotateTemplateMeta = result[0];
console.log('Annotated template count :: ' + result[0].length);
if (selectedOption === 'All') {
$scope.fetchRapidTemplates(selectedOption);
} else {
$scope.prepareTemplateList(selectedOption);
}
});
};
$scope.fetchRapidTemplates = function(selectedOption) {
ServiceFactory.PagesService.getAllPages().$promise.then(function(result) {
$scope.rapidTemplateMeta = result[0];
console.log('Rapid template count :: ' + result[0].length);
$scope.prepareTemplateList(selectedOption);
});
};
$scope.prepareTemplateList = function(selectedOption) {
$scope.itemsPerPage = 8;
var getPaginatedTemplateList = 'getList';
//$scope.currentPage = 0;
if (selectedOption === 'Annotate') {
$scope.annotateTemplateMeta.forEach(function(annotate) {
var templateObject = {};
templateObject = { id: annotate.id, name: annotate.name, type: "Annotate", dynamic_entity: annotate.dynamic_entity };
$scope.templatesList.push(templateObject);
});
} else if (selectedOption === 'Rapid') {
$scope.rapidTemplateMeta.forEach(function(rapidTemplate) {
var templateObject = {};
templateObject = { id: rapidTemplate._id, name: rapidTemplate.name, type: "Component", dynamic_entity: rapidTemplate.pageObj.entity };
$scope.templatesList.push(templateObject);
});
} else {
$scope.annotateTemplateMeta.forEach(function(annotate) {
var templateObject = {};
templateObject = { id: annotate.id, name: annotate.name, type: "Annotate", dynamic_entity: annotate.dynamic_entity };
$scope.templatesList.push(templateObject);
});
$scope.rapidTemplateMeta.forEach(function(rapidTemplate) {
var templateObject = {};
templateObject = { id: rapidTemplate._id, name: rapidTemplate.name, type: "Component", dynamic_entity: rapidTemplate.pageObj.entity };
$scope.templatesList.push(templateObject);
});
$scope.totalItems = $scope.templatesList.length;
$scope.maxSize = 5;
}
console.log($scope.templatesList);
console.log($scope.currentPage);
};
$scope.setPage = function(pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
alert('Page changed to: ' + $scope.currentPage);
$log.log('Page changed to: ' + $scope.currentPage);
};
$scope.init();
$scope.$watch('currentPage + numPerPage', function() {
console.log('is it coming.....?');
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage)
, end = begin + $scope.itemsPerPage;
$scope.filteredTemplates = $scope.templatesList.slice(begin, end);
});
});
is there anything wrong with my code?
please provide some inputs on this.
See how to create a custom paging which will deal with the performance and you will have control on the paging control style.
Create a service to set a paging object
var rapid = angular.module('rapid');
rapid.service('pagerOptions', function () {
'use strict';
return {
newOptions: function () {
return {
totalItems: 0,
itemsPerPage: 50,
page: 1,
sortBy: '',
isASC: true,
filters: null,
sortOptions: {
by: '',
isASC: true,
sort: function (sortBy) {
if (sortBy === this.parent.sortBy) {
this.parent.isASC = !this.parent.isASC;
} else {
this.parent.sortBy = sortBy;
this.parent.isASC = true;
}
this.parent.resetPage();
if (typeof this.parent.onPageChange === "function")
this.parent.onPageChange();
}
},
resetPage: function () {
this.page = 1;
},
goToPage: function (page) {
this.page = page;
if (typeof this.onPageChange === "function")
this.onPageChange();
},
init: function () {
this.sortOptions.parent = this; // it allows the Methods object to know who its Parent is
delete this.init; // if you don't need the Init method anymore after the you instanced the object you can remove it
return this; // it gives back the object itself to instance it
}
}.init();
}
};
})
Create a custom directive to design paging template as follows,
rapid.directive('footerPager', function () {
return {
restrict: 'E',
transclude: true,
template:
'<div class="col-xs-9 text-right" ng-cloak>\
<span ng-if="options.totalItems > options.itemsPerPage">\
<pagination \
ng-model="options.page" \
total-items="options.totalItems" \
items-per-page="options.itemsPerPage" \
ng-change="options.goToPage(options.page)" \
max-size="5" rotate="false" boundary-links="true" \
previous-text="‹" next-text="›" \
first-text="«" last-text="»" \
class="pagination-sm">\
</pagination>\
</span>\
</div>\,
scope: {
options: '='
}
}
});
In cshtml file use the above created custom directive as follows,
<footer-pager options="pagingOptions" id="footer"/>
In corresponding controller.js file create and set the 'pagerOptions' object by calling the 'newOptions' method of the above created service,
rapid.controller('HomeListController',
['$scope', 'adminSvc','pagerOptions',
function auditLogCtrl($scope,adminSvc,pagerOptions) {
$scope.pagingOptions = pagerOptions.newOptions();
$scope.pagingOptions.sortBy = "CreatedDate";
$scope.pagingOptions.itemsPerPage = 10;
$scope.pagingOptions.onPageChange = loadData; //loadData is a method load the data to the page.
var numberOfSearchPerfomed = 0;
$scope.data= {};
function loadData() {
$scope.pagingOptions.filters = selectedFilters;
service.getData(vm.pagingOptions) //Method will fetch data from db and show in the view based on pagingOptions.
.success(function (result) {
$scope.data= result.Data;
$scope.pagingOptions.totalItems = result.TotalCount; // TotalCount represents the total number of records not page wise.
$scope.enableResetButton = numberOfSearchPerfomed >= 1;
});
}
loadData();
}])

Undefined property knockout.js + mvc

I have a masterDetails view that I populate with some data from a db (it populates fine). I added a button to the master details view, to add a step to my workflow.
My Viewmodel:
/// <reference path="_references.js" />
var viewModel = function (data) {
var self = this;
self.SelectedWorkflow = ko.observable({
Steps: ko.observableArray([]),
Name: ko.observable("")
});
self.Workflows = ko.observableArray(data);
self.addStep = function() {
self.Steps.push(new Step(SelectedWorkflow, "Assignment here", "01/01/2014", "dd:mm:ss", "mail"));
};
};
function Step(workflow,assignment, enddate, reminder, mailaddresses, type) {
var self = this;
self.Workflow = workflow;
self.StepNumber = 0;
self.Assignment = assignment;
self.Enddate = enddate;
self.Reminder = reminder;
self.MailAddresses = mailaddresses;
self.Type = type;
};
/// <reference path="workflowdetails-vm.js" />
$(document).ready(function () {
$.ajax({
url: "/WorkflowDetails/Index/",
type: "POST",
data: {},
success: function (data) {
var workflowlist = ko.mapping.fromJS(data.Workflows);
vm = new viewModel(workflowlist);
ko.applyBindings(vm);
}
});
$(".right-aligned-section").hide();
});
$(document).delegate(".show-details", "click", function () {
$(".right-aligned-section").fadeIn();
var workflow = ko.dataFor(this);
vm.SelectedWorkflow(workflow);
});
My View:
<div class="left-aligned-section">
<ul data-bind="foreach: Workflows()">
<li>
<div class="workflow-item-border">
<div>
<label data-bind="text: Name"></label>
</div>
<div>
<label data-bind="text: StartDate"></label>
</div>
<div>
Show Details
</div>
</div>
</li>
</ul>
</div>
<div class="right-aligned-section" data-bind="with: SelectedWorkflow">
<div class="steps-header">
<div class="left-aligned-div"><strong>Steps for </strong></div>
<div class="left-aligned-div" data-bind="text: Name"></div>
</div>
<button data-bind="click: addStep">add step</button>
<ul data-bind="foreach: Steps">
<li>
<div class="step-item-border">
<div>
<div class="step-label">Stepnumber: </div>
<div style="font-weight: bold" data-bind="text: StepNumber"></div>
</div>
<div>
<div class="step-label">Assignment: </div>
<div style="font-weight: bold" data-bind="text: Assignment"></div>
</div>
<div>
<div class="step-label">Mails: </div>
<div style="font-weight: bold" data-bind="text: MailAddresses"></div>
</div>
<div>
<div class="step-label">End Date: </div>
<div style="font-weight: bold" data-bind="text: Enddate"></div>
</div>
<div>
<div class="step-label">Type: </div>
<div style="font-weight: bold" data-bind="text: Type"></div>
</div>
</div>
</li>
</ul>
</div>
When I press the button - nothing happens. The error I receive is:
ReferenceError: Steps is not defined
I know what it means, but I'm not proficient enough in web development to actually fix it. Please help.
Probably this would work:
var viewModel = {};
viewModel.SelectedWorkflow = {
Steps: ko.observableArray([]),
Name: ko.observable("")
};
viewModel.Workflows = ko.observableArray(data);
viewModel.addStep = function () {
viewModel.SelectedWorkflow.Steps.push(
new Step(SelectedWorkflow, "Assignment here", "01/01/2014", "dd:mm:ss", "mail"));
}
}
You have forgotten about SelectedWorkflow.Steps I think...
Looks like you forgot a this before the Steps.push....
Edit: I have made some further changes to the click handler function
var viewModel = function (data) {
this.SelectedWorkflow = ko.observable({
Steps: ko.observableArray([]),
Name: ko.observable("")
});
this.Workflows = ko.observableArray(data);
this.addStep = function (selectedWorkflow) { // the current context is passed in from the click data-bind
selectedWorkflow.Steps.push(new Step(selectedWorkflow, "Assignment here", "01/01/2014", "dd:mm:ss", "mail"));
}
}
Edit: Fixed code

durandal messagebox close button on top

by default durandal messagebox box is like this : and named as : messageBox.html
<div class="messageBox">
<div class="modal-header">
<h3 data-bind="html: title"></h3>z
</div>
<div class="modal-body">
<p class="message" data-bind="html: message"></p>
</div>
<div class="modal-footer" data-bind="foreach: options">
<button class="btn" data-bind="click: function () { $parent.selectOption($data); }, html: $data, css: { 'btn-primary': $index() == 0, autofocus: $index() == 0 }"></button>
</div>
</div>
now here, i would like to put X button on header right side :
<div class="modal-header">
<h3 data-bind="html: title"></h3>
<a>X</a>
</div>
so i put the X in modal-header, but i am not able to figure out where and what code should write,so when user click on X , the popup will closed.
messageBox.js is like this :
define(function() {
var MessageBox = function(message, title, options) {
this.message = message;
this.title = title || MessageBox.defaultTitle;
this.options = options || MessageBox.defaultOptions;
};
MessageBox.prototype.selectOption = function (dialogResult) {
this.modal.close(dialogResult);
};
MessageBox.defaultTitle = '';
MessageBox.defaultOptions = ['Ok'];
return MessageBox;
});
You need to do knockout binding to the function closing modal
<div class="modal-header">
<h3 data-bind="html: title"></h3>
<span data-bind="click: function () { $parent.close(); }>X</span>
</div>
While Your JS file looks like:
define(function() {
var MessageBox = function(message, title, options) {
this.message = message;
this.title = title || MessageBox.defaultTitle;
this.options = options || MessageBox.defaultOptions;
};
MessageBox.prototype.selectOption = function (dialogResult) {
this.modal.close(dialogResult);
};
MessageBox.prototype.close = function () {
this.modal.close();
};
MessageBox.defaultTitle = '';
MessageBox.defaultOptions = ['Ok'];
return MessageBox;
});

emberjs arraycontroller issue

I am new to Ember and am having an issue. I would like the user to be able to select a number of workstations, and when they hit the next button, I would like the controller to create a number of objects equal to the number the user selected. Once they are taken to the next screen I want to view to append a number of divs with the questions equal to the number the user selected.
I have this for the app.js:
//Initialize the application
App = Ember.Application.create({
rootElement: '#main'
});
//Initialize the data model
App.CustomerController = Ember.Object.extend({
first: null,
last: null,
email: null,
phone: null,
clinic: null,
number: null
});
App.Workstation = Ember.Object.extend({
id: null,
title: null,
newOrExisting: null,
cabling: null
});
App.workstationController = Ember.ArrayController.create({
content: [],
num: null,
init: function() {
this.set('content',[]);
var num = this.get('num');
var tempId = Date.now();
var ws = App.Workstation.create({
id: tempId
});
this.pushObject(ws);
}
});
App.selectNoComputers = ["1", "2", "3", "4", "5"];
App.workstationSelect = ["Counter 1", "Counter 2", "Counter 3", "Counter 4", "Office 1", "Office 2", "Office 3"];
App.yesNo = ["New", "Existing"];
App.Router.map(function(match) {
match("/").to("captcha");
match("/customer").to("customer");
match("/wsnum").to("computers");
match("/overview").to("overview");
});
App.CaptchaRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('captcha');
}
});
App.CustomerRoute = Ember.Route.extend();
App.ComputersRoute = Ember.Route.extend();
App.OverviewRoute = Ember.Route.extend({
});
App.initialize();
And this for my html:
<script type="text/x-handlebars" data-template-name="overview">
<div class="navbar">
<div class="navbar-inner">
<div class="progress-bar-label-div">
Progress:
</div>
<div class="progress-bar-div">
<div class="progress progress-striped">
<div class="bar" style="width:60%;"></div>
</div>
</div>
<div class="btn-group pull-right">
{{#linkTo "computers" class="btn"}}
Prev
{{/linkTo}}
</div>
</div>
</div>
<div class="row-a top">
<div class="pull-left" >
<h3>Workstation Overview</h3>
</div>
<div class="pull-right">
</div>
</div>
{{#each App.workstationController}}
<div class="workstation-b">
<div class="row-b">
<div class="pull-left workstation-title" >
<h4>{{id}}</h4>
</div>
<div class="pull-right form-inputs input-text">
<a class="btn btn-primary" >
Start
</a>
</div>
</div>
<div class="row-b">
<div class="pull-left questions">
What station will this be?
</div>
<div class="pull-right form-inputs input-text">
{{view Ember.Select prompt="Please Select" contentBinding="App.workstationSelect"}}
</div>
</div>
<div class="row-b">
<div class="pull-left questions">
Is this computer a new purchase or replacing and existing workstation?
</div>
<div class="pull-right form-inputs input-text">
{{view Ember.Select prompt="Please Select" contentBinding="App.yesNo"}}
</div>
</div>
</div>
{{/each}}
</script>
I'm sure I'm missing something pretty easy, but any help is appreciated.
I put together a fiddle to illustrate my problem.
Working fiddle: http://jsfiddle.net/mgrassotti/xtNXw/3/
Relevant changes: Added an observer to listen for changes to the num property. When it changes, the content array is reset and then an appropriate number of blank workstation objects are created.
App.workstationController = Ember.ArrayController.create({
content: [],
num: null,
init: function() {
this.set('content',[]);
},
addBlankWorkstation: function() {
var tempId = Date.now();
var ws = App.Workstation.create({
id: tempId
});
this.pushObject(ws);
}
});
App.workstationController.addObserver( 'num', function() {
var num = this.get('num');
this.set('content',[]);
for (var i=0;i<num;i++) {
this.addBlankWorkstation();
}
});
I hesitated to say working fiddle above since there are many things that might be worth refactoring. You'll find most of the complexity could be reduced by following ember naming conventions. Suggest looking at latest guides for more detail.

Categories

Resources