KnockoutJS nested foreach not defined - jquery-mobile

I'll keep it short. My view model looks like this:
var ViewModel = {
Cameras: ko.observableArray(),
Current: ko.observableArray()
};
and I want to do something like this:
<!-- ko foreach: Cameras -->
<div data-role="collapsible">
<h3 data-bind="text: CameraName"></h3>
<!-- ko foreach: Current -->
<img data-bind="attr: { src: URL }" />
<!-- /ko -->
</div>
<!-- /ko -->
CameraName property is from Cameras array and URL property is from Current array, but when I do this I get "Current is not defined". I've looked into nested foreach but there must be something I'm not understanding properly.

Current has to be a property of the item in Cameras.
Like so...
var Camera = function() {
this.Current = ...
}
You could try Knockout 2.1's $parent.
<!-- ko foreach: Cameras -->
<div data-role="collapsible">
<h3 data-bind="text: CameraName"></h3>
<!-- ko foreach: $parent.Current -->
<img data-bind="attr: { src: URL }" />
<!-- /ko -->
</div>
<!-- /ko -->

Related

Why does the clone remove method doesn't work after the function was altered?

I have been trying to delete specific clone data using JQuery -UI. i had to change my functions recently since then the remove button doesn't work. Please help me find my error.
My whole function that includes, Multidimensional Arrays along with form cloning! check out my remove function which i think has no problem in it.
$(function() {
var questionHolder = $('.question').clone(true);
$("#addQuestion").on('click', function(e) {
e.preventDefault();
var str = $("p.number:last").text(),
newValue = parseInt(str, 10) + 1;
var newQ = questionHolder.clone();
newQ.find('input, textarea')
.each(function() {
this.name = this.name.replace(/\[(\d+)\]/, '[' + newValue + ']');
})
.end()
.find('.number')
.html(newValue)
.end()
.appendTo('#questioncontainer')
.after('<br><button class="addQuestion_delete btn btn-danger" type="button">Remove Parent Clone</button><br>');
$(".addQuestion_delete").click(function(e) {
$(this).closest("#questioncontainer").remove();
e.preventDefault();
});
});
$('body').on('click', '.addAnswer', function(e) {
e.preventDefault();
var group = $(this).parent();
parent = $(this).parent().parent();
group.find(".answer:last")
.clone(true)
.find('input, textarea')
.each(function() {
this.name = this.name.replace(/\[(\d+)\]$/,
function(str, p1) {
return '[' + (parseInt(p1, 10) + 1) + ']';
});
})
.end()
.appendTo(
group.find('.answerContainer'))
.after('<button class="addAnswer_delete btn btn-danger" type="button"><i class="fa fa-minus"></i>Remove Child clone</button><br><br><br>');
$(".addAnswer_delete").click(function(e) {
$(this).closest(".answerContainer").remove();
e.preventDefault();
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- parent container -->
<div id="questioncontainer">
<!-- parent that clones -->
<div style="border:1px solid black; width:400px; padding:20px; margin-bottom:10px;" class="question border p-5 mt-3 shadow">
<!-- clone items inputs/textareas/files -->
<div class="row">
<div class="col-lg-6">
<!-- Educational Institute -->
<input oninput="checkCompany()" id="company" name="employer[1]" type="text" class="input-form track track_exp_qua" data-score=20>
<span class="bar"></span>
<label class="input-label"> Company <span id="text" class="required"> </span></label>
<!-- Educational Institute -->
<p class="validate text-danger pt-2" id="company_error"></p>
</div>
<div class="col-lg-6">
<!-- Job title -->
<input oninput="checkJobTitle()" id="job_title" name="job_title[1]" type="text" class="input-form track track_exp_qua" data-score=10>
<span class="bar"></span>
<label class="input-label"> Job Title <span id="text" class="required"> </span></label>
<!-- Job title -->
<p class="validate text-danger pt-2" id="job_title_error"></p>
</div>
</div>
<div class="justify-content-center pb-4">
<h4>Below is the child clone</h4>
</div>
<!-- child container -->
<div style="border:1px solid red; padding:20px;" class="answerContainer">
<div class="answer">
<div class="row">
<!-- best project url -->
<div class="col-lg-6">
<input name="best_project[1][1]" type="text" class="input-form track track_exp_qua" data-score=10>
<span class="bar"></span>
<label class="input-label">Best Project<small style="color:#FFBF00;"> (URL's Only) </small> <span id="text" class="optional"> </span></label>
</div>
<!-- best project url -->
</div>
<br>
</div>
</div>
<!-- clone items inputs/textareas/files end-->
<br>
<button class="addAnswer btn btn-info" href="#"><i class="fa fa-plus"></i> Add Child</button>
</div>
<!-- parent that clones end-->
</div>
<!-- parent container end -->
<br>
<button id="addQuestion" class="btn btn-success" href="#"> <i class="fa fa-plus"></i> Add Parent </button>
Some of your objects were too ambigous, so things were not going to work as you expected.
Consider the following example.
$(function() {
function updateName(i, n) {
i = $(i);
var o = i.attr("name");
if (n != undefined) {
i.attr("name", o.replace(/\[(\d+)\]/, '[' + n + ']'));
} else {
i.attr("name", o.replace(/\[(\d+)\]$/,
function(str, p1) {
return '[' + (parseInt(p1, 10) + 1) + ']';
}));
}
return true;
}
function makeDel(cnt, pClass, tObj) {
return $("<button>", {
class: pClass + " btn btn-danger",
type: "button"
}).html(cnt).insertAfter(tObj);
}
function addQuestion(event) {
var self = $(event.target);
event.preventDefault();
var newValue = $(".question").length + 1;
var newQ = $(".question").eq(0).clone(true);
$("input, textarea", newQ).each(function() {
updateName(this, newValue);
});
newQ.appendTo("#questioncontainer");
var newD = makeDel("Remove Parent Clone", "addQuestion_delete", newQ);
newD.click(function(e) {
e.preventDefault();
newQ.remove();
$(this).remove();
});
}
function addAnswer(event) {
var self = $(event.target);
event.preventDefault();
var group = self.parent().find(".answerContainer");
var newA = $(".answer:last", group).clone(true);
$("input, textarea", newA).each(function() {
updateName(this);
});
newA.appendTo(group);
var newD = makeDel("<i class='fa fa-minus'></i> Remove Child clone", "addAnswer_delete", group);
newD.click(function(e) {
e.preventDefault();
newA.remove();
$(this).remove();
});
}
$("body").on("click", "#addQuestion", addQuestion);
$('body').on('click', '.addAnswer', addAnswer);
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- parent container -->
<div id="questioncontainer">
<!-- parent that clones -->
<div style="border:1px solid black; width:400px; padding:20px; margin-bottom:10px;" class="question border p-5 mt-3 shadow">
<!-- clone items inputs/textareas/files -->
<div class="row">
<div class="col-lg-6">
<!-- Educational Institute -->
<input oninput="checkCompany()" id="company" name="employer[1]" type="text" class="input-form track track_exp_qua" data-score=20>
<span class="bar"></span>
<label class="input-label"> Company <span id="text" class="required"> </span></label>
<!-- Educational Institute -->
<p class="validate text-danger pt-2" id="company_error"></p>
</div>
<div class="col-lg-6">
<!-- Job title -->
<input oninput="checkJobTitle()" id="job_title" name="job_title[1]" type="text" class="input-form track track_exp_qua" data-score=10>
<span class="bar"></span>
<label class="input-label"> Job Title <span id="text" class="required"> </span></label>
<!-- Job title -->
<p class="validate text-danger pt-2" id="job_title_error"></p>
</div>
</div>
<div class="justify-content-center pb-4">
<h4>Below is the child clone</h4>
</div>
<!-- child container -->
<div style="border:1px solid red; padding:20px;" class="answerContainer">
<div class="answer">
<div class="row">
<!-- best project url -->
<div class="col-lg-6">
<input name="best_project[1][1]" type="text" class="input-form track track_exp_qua" data-score=10>
<span class="bar"></span>
<label class="input-label">Best Project<small style="color:#FFBF00;"> (URL's Only) </small> <span id="text" class="optional"> </span></label>
</div>
<!-- best project url -->
</div>
<br>
</div>
</div>
<!-- clone items inputs/textareas/files end-->
<br>
<button class="addAnswer btn btn-info" href="#"><i class="fa fa-plus"></i> Add Child</button>
</div>
<!-- parent that clones end-->
</div>
<!-- parent container end -->
<br>
<button id="addQuestion" class="btn btn-success" href="#"> <i class="fa fa-plus"></i> Add Parent </button>
Objects are created and referenced a bit better, so it's easier to manipulate them and remove them as needed. Anytime you are doing the same thing multiple times, you could consider creating a function for it.

Display Data from Firebase in V dialog with V model in Vuetify with Vue.JS

I can't believe it will not solve my problem, and it will not display the data from database to v dialog/ Can anyone who can point my problem? Anyway this is my code. The only way to do is to display the data from Firebase Realtime Database to V Dialog.
<template slot="items" scope="{ item }" :prop="item['.key']">
<td>{{ item.name }}</td>
<td>
<div v-if="!item.edit">
<v-btn fab dark slot="activator" v-show="!hidden" small #click="setupdateProduct(item['.key'])" class="teal lighten-2">
<v-icon dark>edit</v-icon>
</v-btn>
</div>
<div v-else>
<v-fab-transition>
<v-dialog v-model="dialog" fullscreen transition="dialog-bottom-transition" :overlay=true>
<!-- <form #submit.click="editProduct"> -->
<v-card>
<v-toolbar dark class="info">
<v-btn icon #click.native="dialog = false" dark>
<v-icon>arrow_back</v-icon>
</v-btn>
<v-toolbar-title>Products</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn dark flat type="submit">Save</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-list three-line subheader>
<v-subheader>*means required field</v-subheader>
<v-card-text>
<v-container fluid>
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<v-text-field
name="name"
label="Product Title*"
id="name"
v-model="item.name"
></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
</v-list>
</v-card>
<!-- </form> -->
</v-dialog>
</v-fab-transition>
</div>
</td>
</template>
//In my methods
setupdateProduct(key) {
productRef.child(key).update({ edit: true })
}

Foreach not updating HTML list elements

Using knockout 2.2.0
I'm trying to use the same dialog for add and edit. I have the code mostly working, but when I replace the observable with the new edited one, it doesn't cause an update in the foreach (or at least it continues to display the old values) It does update the actual model, as I can see in dev tools. I even tried to force an update with .valueHasMutated(), but with no luck.
self.editReference = function () {
self.isEdit(true);
self.open();
self.dialogReferences(this);
};
self.saveEditReference = function () {
self.references.replace(this, self.dialogReferences);
self.references.valueHasMutated();
self.dialogReferences(newReferences());
self.close();
};
And here is the some of the partial view with the references section of HTML code:
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"><b>Name: </b><!-- ko text:name --><!-- /ko--><br /><b>Company: </b><!-- ko text:company --><!-- /ko--><span class="ui-icon ui-icon-closethick"></span><span class="ui-icon ui-icon-wrench"></span></li>
</ul>
Thanks to CrimsonChris for pointing out my bug. The updated code below works as expected.
The approach is to have a reference you are editing, in addition to the references in your array. When you start to edit, you copy the values from the array to your edit reference. When you save the edit, you copy them back. There is no need for valueHasMutated for this to work.
function reference(name, company) {
return {
name: ko.observable(name),
company: ko.observable(company)
};
}
// Copy r1 into r2
reference.copy = function(r1, r2) {
r2.name(r1.name());
r2.company(r1.company());
}
var self = {
editingReference: undefined,
dialogReferences: reference('', ''),
references: ko.observableArray([
reference('One', 'First Company'),
reference('Two', '2nd Company')
]),
dialogIsOpen: ko.observable(false),
open: function() {
self.dialogIsOpen(true);
},
close: function() {
self.dialogIsOpen(false);
}
};
self.editReference = function(item) {
self.editingReference = item;
self.open();
reference.copy(item, self.dialogReferences);
};
self.removeReference = function(item) {
self.references.remove(item);
self.close();
};
self.saveEditReference = function(item) {
reference.copy(item, self.editingReference);
self.close();
};
ko.applyBindings(self);
<link href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min.js"></script>
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"> <b>Name: </b>
<!-- ko text:name() -->
<!-- /ko-->
<br /> <b>Company: </b>
<!-- ko text:company() -->
<!-- /ko--> <span class="ui-icon ui-icon-closethick"></span>
<span class="ui-icon ui-icon-wrench"></span>
</li>
</ul>
<div data-bind="if: dialogIsOpen">
<div data-bind="with:dialogReferences">
<label>Name</label>
<input data-bind="value:name" />
<br/>
<label>Company</label>
<input data-bind="value:company" />
<input type="button" value="Save" data-bind="click: $parent.saveEditReference" />
</div>
</div>

AngularJS doesn't work in MVC Partial Views

I'm currently working on a ASP.NET MVC project. The sites of the web application are created with Bootstrap. Later I added some AngularJS script to be able to translate the page into different languages. This works fine for all the pages, but not so if a partial view is loaded from a page.
So, for example I have a page to search for rollout objects by name or host name. On the page all the angular expressions in curly braces are evaluated properly and are replaced with strings in several languages by using a translate script. Now if I filter the objects by one of the three attributes the partial view for that page is loaded showing the results of the search, but here are the angular expressions not evaluated and it just shows the expressions themselves.
Here is the page where it works properly:
#{
ViewBag.Title = "{{ 'ROLLOUT-OBJECT_MANAGEMENT.TITLE' | translate }}";
}
<!-- html -->
<div style="font-size: 20px; margin-top: 20px; margin-bottom: 20px;">
<div class="gray-background list-group-item" translate="{{'ROLLOUT-OBJECT_MANAGEMENT.TITLE'}}"></div>
</div>
<div class="list-group">
<div class="gray-background list-group-item">
<div class="row margin-bottom">
<div class="col-md-3">
<h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.FIRST_NAME'}}"></h6>
</div>
<div class="col-md-3">
<h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.SURNAME'}}"></h6>
</div>
<div class="col-md-3">
<h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.HOST_NAME'}}"></h6>
</div>
</div>
<div class="row margin-bottom">
<div class="col-md-3">
<!-- referenced in getPartial() -->
<input type="text" class="form-control" id="iFirstName" name="iFirstName" placeholder="">
</div>
<div class="col-md-3">
<!-- referenced in getPartial() -->
<input type="text" class="form-control" id="iSurName" name="iSurName" placeholder="">
</div>
<div class="col-md-3">
<!-- referenced in getPartial() -->
<input type="text" class="form-control" id="iHostName" name="iHostName" placeholder="">
</div>
<div class="col-md-3">
<!-- getPartial() added to click through javascript-->
<button type="submit" class="btn btn-primary btn-block" id="iButton"><span translate="{{'ROLLOUT-OBJECT_MANAGEMENT.BUTTON_SEARCH'}}"></span><span class="white-color glyphicon glyphicon-search"></span></button>
</div>
</div>
</div>
</div>
<div class="list-group">
<div class="gray-background list-group-item">
<h5><span translate="{{'ROLLOUT-OBJECT_MANAGEMENT.RESULTS'}}"></span><span class="purple-color glyphicon glyphicon-globe"></span></h5>
</div>
<!-- referenced in getPartial() -->
<div class="gray-background list-group-item">
<div class="row">
<div class="col-md-12" id="partialViewContainer">
#{Html.RenderPartial("_RolloutObjectManagementResultsPartial");}
</div>
</div>
</div>
</div>
<!-- layout -->
#Styles.Render(
"~/content/chosen/chosen.css",
"~/content/chosen/prism.css",
"~/content/chosen/style.css",
"~/content/bootstrap.css",
"~/content/Site.css")
<!-- javascript -->
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/chosen/chosen.jquery.js"></script>
<script src="~/Scripts/chosen/prism.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script>
var config = {
'.chosen-select': {},
'.chosen-select-deselect': { allow_single_deselect: true },
'.chosen-select-no-single': { disable_search_threshold: 10 },
'.chosen-select-no-results': { no_results_text: 'Oops, nothing found!' },
'.chosen-select-width': { width: "95%" }
}
for (var selector in config) {
$(selector).chosen(config[selector]);
}
</script>
<script>
//add functionality to button
$('#iButton').click(function () {
getPartial('0');
});
</script>
<script>
function previous() {
var temp = document.getElementById("hPage").value;
//alert(temp);//debug
if (temp > 0) {
temp = --temp;
}
getPartial(temp);
}
function next() {
var temp = document.getElementById("hPage").value;
//alert(temp);//debug
temp = ++temp;
getPartial(temp);
}
</script>
<script>
function getPartial(newPage) {
//get search values
var tempFirst = document.getElementById("iFirstName");
var tempSur = document.getElementById("iSurName");
var tempHost = document.getElementById("iHostName");
var firstResult = tempFirst.value;
var surResult = tempSur.value;
var hostResult = tempHost.value;
//ajax call
$.ajax({
url: "_RolloutObjectManagementResultsPartial",
type: "POST",
data: { firstName: firstResult, surName: surResult, hostName: hostResult, page: newPage, count: 10 },
dataType: "html",
error: function (xhr) {
//alert(xhr.responseText);//debug
},
success: function (result) {
$("#partialViewContainer").html(result).find("select").each(function () {
$(this).chosen({});
})
},
complete: function () {
//alert("everything worked");//debug
}
});
}
</script>
And here is the partial view where it doesn't work (important are the expressions in {{...}}:
<!-- Import needed namespaces -->
#using RolloutTool.BusinessLayer.Foundation
#using RolloutTool.Utility
<!-- Initializing needed variables -->
#{
List<RolloutObject> RolloutObjects = ViewContext.Controller.ViewBag.RolloutObjects;
List<Cluster> Clusters = ViewContext.Controller.ViewBag.Clusters;
string name = "";
int count = 0;
string rowID = "";
int page = 0;
if (ViewContext.Controller.ViewBag.Page != null)
{
page = ViewContext.Controller.ViewBag.Page;
}
}
<!-- html elements -->
<div class="row">
<div class="col-md-12">
<table class="table">
<thead>
<tr>
<th style="width:25%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.EMPLOYEE'}}"></h6></th>
<th style="width:20%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.WORK_STATION'}}"></h6></th>
<th class="text-center" style="width:15%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.EDIT'}}"></h6></th>
<th class="text-center" style="width:25%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.CLUSTER'}}"></h6></th>
<th class="text-center" style="width:15%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.ASSIGN'}}"></h6></th>
</tr>
</thead>
<tbody>
<!-- creating all RolloutObject Table rows -->
#foreach (RolloutObject ro in RolloutObjects)
{
<!-- generating rowID -->
rowID = "row" + Convert.ToString(count);
count++;
<!-- generating the full employee name -->
name = Functions.TryGetValue(ro.Employee.FirstName) + " " + Functions.TryGetValue(ro.Employee.SecondName) + " " + Functions.TryGetValue(ro.Employee.Name);
<tr id="#rowID">
<td>#name</td>
<td id="#Convert.ToString(rowID + "_hn")">#Convert.ToString(Functions.TryGetValue(ro.Hostname))</td>
<!-- generate link to right rolloutobjectedit -->
<td class="text-center"><span class="btn-pencil glyphicon glyphicon-pencil blue-color glyph-hov" onclick="location.href='#Url.Action("RolloutObjectEdit", "RolloutObject", new {hostName = ro.Hostname })'"></span></td>
<!-- generating the link for cluster addition and populating cluster dropdown -->
<td class="text-center">
<div class="row">
<div class="col-sm-12">
<select class="chosen-select no-margin" style="width:100%" id="#Convert.ToString(rowID + "_cl")" name="iCluster" data-placeholder="Cluster">
#if (ro.Cluster != null)
{
<option selected>#Convert.ToString(Functions.TryGetValue(ro.Cluster.Name))</option>
}
else
{
<option></option>
}
#foreach (Cluster cluster in Clusters)
{
<option>#Convert.ToString(Functions.TryGetValue(cluster.Name))</option>
}
</select>
</div>
</div>
</td>
<td class="text-center"><span class="btn-ok glyphicon glyphicon-ok green-color glyph-hov" onclick="callAjax('#rowID')" /></td>
</tr>
}
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-12">
<input class="hidden" id="hPage" value="#Convert.ToString(page)" />
<nav>
<ul class="pager">
<li class="pull-left"><a class="btn-paging glyphicon glyphicon-arrow-left" onclick="previous()"></a></li>
<li class="pull-right"><a class="btn-paging glyphicon glyphicon-arrow-right" onclick="next()"></a></li>
</ul>
</nav>
</div>
</div>
<!-- javascript -->
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/chosen/chosen.jquery.js"></script>
<script src="~/Scripts/chosen/prism.js"></script>
<script>
function callAjax(idRow) {
//get row values
var tempTD = document.getElementById(idRow + "_hn");
var tempSelect = document.getElementById(idRow + "_cl");
var tempHostName = tempTD.textContent;
var tempCluster = tempSelect.options[tempSelect.selectedIndex].text;
//ajax call
$.ajax({
url: "AddToCluster",
type: "POST",
data: { clusterName: tempCluster, hostName: tempHostName },
dataType: "html",
error: function (xhr) {
alert(xhr.responseText);
},
success: function (result) {
},
complete: function () {
//alert("everything worked");//debug
}
});
}
</script>
<script>
function previous() {
var temp = document.getElementById("hPage").value;
//alert(temp);//debug
if (temp > 0) {
temp = --temp;
}
getPartial(temp);
}
function next() {
var temp = document.getElementById("hPage").value;
//alert(temp);//debug
temp = ++temp;
getPartial(temp);
}
</script>
<script>
function getPartial(newPage) {
//get search values
var tempFirst = document.getElementById("iFirstName");
var tempSur = document.getElementById("iSurName");
var tempHost = document.getElementById("iHostName");
var firstResult = tempFirst.value;
var surResult = tempSur.value;
var hostResult = tempHost.value;
//ajax call
$.ajax({
url: "_RolloutObjectManagementResultsPartial",
type: "POST",
data: { firstName: firstResult, surName: surResult, hostName: hostResult, page: newPage, count: 10 },
dataType: "html",
error: function (xhr) {
alert(xhr.responseText);
},
success: function (result) {
$("#partialViewContainer").html(result).find("select").each(function () {
$(this).chosen({});
})
},
complete: function () {
//alert("everything worked");//debug
}
});
}
</script>
This is the _Layout.cshtml where the scripts are contained and loaded:
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - {{ 'TITLE.PROGRAM' | translate }}</title>
#Styles.Render(
"~/Content/css",
"~/Content/flag-icon-css-master/assets/docs.css",
"~/Content/flag-icon-css-master/css/flag-icon.min.css",
"~/Content/Site.css")
<script src="~/Scripts/angular/angular.js"></script>
<script src="~/Scripts/angular/angular-translate.js"></script>
<script src="~/Scripts/angular/angular-cookies.min.js"></script>
<script src="~/Scripts/angular/translate.js"></script>
<script src="~/Scripts/angular/angular-route.min.js"></script>
<script src="~/Scripts/angular/angular-translate-storage-cookie.min.js"></script>
<script src="~/Scripts/angular/angular-translate-storage-local.min.js"></script>
</head>
<body ng-controller="Ctrl">
<!-- Here is the html for the navigation bar etc. -->
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
</html>
I am really not an expert on AngularJS as I only wanted to provide some cool translation feature, but I hope you guys have an idea why it doesn't work in the partial views.
Its just that you need to call the partial view using ng-include("'controller/action'"). Apostrophe(') is important while writing url.
Example
<div id="TestDiv" ng-include="templateUrl"></div>
and inside the angular controller
var app = angular.module("Layout", []);
app.controller("LoadPage", function ($scope, $http, $sce) {
//Initially
$scope.templateUrl = '/Home/DefaultPage';
// To dynamically change the URL.
$scope.NewProjFn = function () {
$scope.templateUrl = '/Home/ProjectPage';
};
});
It might well not at all be difficult for you to re-implement it but by using ng-include you also need not to make an ajax call. It do it all by itself which includes ajax call, compilation and display. But the functions like ng-click and other events will not work as its a one time compilation process.

Delay knockout binding evaluation

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.

Resources