Angular with Breeze error Cannot call method of undefined - asp.net-mvc

I'm testing sample CRUD using Angular and Breeze following sample ToDo project.
But for some reason I get error Cannot call method 'getAll' of undefined.
(my odata is hosted on another localhost server, and CORS is enabled, I've tested it)
Here is my code:
Main.js:
var app = {};
app.adminMuscleGroup = angular.module('WebApp', []);
DataService:
app.adminMuscleGroup.dataService = (function (breeze, logger) {
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var servicename = 'http://localhost:23758/odata/';
var manager = new breeze.EntityManager(servicename);
manager.enableSaveQueuing(true);
var dataService = {
getAll: getAll,
};
return dataService;
function getAll() {
var query = breeze.EntityQuery.from("MuscleGroup").orderBy("Name");
return manager.executeQuery(query);
}
})(breeze, app.logger);
Controller:
app.adminMuscleGroup.controller('AdminMuscleGroupCtrl', function($scope) {
var dataService = window.app.dataService;
var logger = window.app.logger;
$scope.items = [];
$scope.getAllMuscleGroups = function () {
dataService.getAll()
.then(querySucceeded)
.fail(queryFailed);
};
$scope.getAllMuscleGroups();
function querySucceeded(data) {
$scope.items = [];
data.results.forEach(function (item) {
$scope.items.push(item);
});
$scope.apply();
logger.info("Fetched all Muscle Groups");
}
function queryFailed(error) {
logger.error(error.message, "Query failed");
}
}
And here is whole error:
ypeError: Cannot call method 'getAll' of undefined
at Object.$scope.getAllMuscleGroups (http://localhost:7122/Scripts/app/AdminMuscleGroup/MuscleGroupController.js:10:21)
at new <anonymous> (http://localhost:7122/Scripts/app/AdminMuscleGroup/MuscleGroupController.js:15:12)
at invoke (http://localhost:7122/Scripts/angular/angular.js:2902:28)
at Object.instantiate (http://localhost:7122/Scripts/angular/angular.js:2914:23)
at http://localhost:7122/Scripts/angular/angular.js:4805:24
at http://localhost:7122/Scripts/angular/angular.js:4384:17
at forEach (http://localhost:7122/Scripts/angular/angular.js:137:20)
at nodeLinkFn (http://localhost:7122/Scripts/angular/angular.js:4369:11)
at compositeLinkFn (http://localhost:7122/Scripts/angular/angular.js:4015:15)
at publicLinkFn (http://localhost:7122/Scripts/angular/angular.js:3920:30) angular.js:5754
(anonymous function)

Try to inject the dataService directly to the controller
app.adminMuscleGroup.controller('AdminMuscleGroupCtrl', function($scope, dataService) {
var dataService = window.app.dataService; // -> delete this

It was stupid mistake, I've changed this line:
var dataService = window.app.dataService;
into this:
var dataService = window.app.adminMuscleGroup.dataService;
Now it works

Related

MVC SignalR not firing from Controller Post Method

When Saving schedule to calendar it must auto update the activity logs on my notification bar in my Home Controller. It saves the data but only show when notification bar is refreshed. It seems that Hub is not starting when saved.
CalendarController.cs
[HttpPost]
public JsonResult SaveSchedule(Schedule s)
{
var userid = User.Identity.GetUserId();
var profile = _context.Profiles.Single(p => p.Id == userid);
var status = false;
if (s.Schedule_ID > 0)
{
//Update
var v = _context.Schedules.Where(a => a.Schedule_ID == s.Schedule_ID).FirstOrDefault();
if (v != null)
{
v.Shift = s.Shift;
}
}
var activitylog = new ActivityLog
{
UserId = userid,
LogDate = DateTime.Now,
Activity = ActivityHelper.GetActivityLog(4, profile.FirstName)
};
// save to data and must be shown on notification bar
_context.ActivityLogs.Add(activitylog);
_context.SaveChanges();
ActivityHub.StartLogging();
status = true;
return new JsonResult { Data = new { status = status } };
}
HomeController.cs
public JsonResult GetLogs()
{
return Json(ActivityHelper.GetActivityLogs(), JsonRequestBehavior.AllowGet);
}
ActivityHub.cs
public class ActivityHub : Hub
{
public static void StartLogging()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
//calls the signalR client part to execute javascript method
context.Clients.All.displayLog();
}
}
My CSHTML
<script>
$(function () {
var activityFromHub = $.connection.activityHub;
$.connection.hub.start().done(function () {
FetchLogs();
});
activityFromHub.client.displayLog = function () {
console.log('Hub Started');
FetchLogs();
}
function FetchLogs() {
$.ajax({
type: 'GET',
url: '/Home/GetLogs',
datatype: 'json',
success: function (data) {
$("#logs tr").remove();
data = $.parseJSON(data);
if (data.length > 0) {
.... do some append here
}
},
error: function (error) {
alert("error");
}
});
}
});
</script>
ActivityHelper.cs
static readonly string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
public static class ActivityHelper
{
public static string GetActivityLogs()
{
string sqlCommand = #"my select query here";
try
{
var messages = new List<ActivityLog>();
using(var connection = new SqlConnection(connString))
{
connection.Open();
using (SqlConnection con = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand(sqlCommand, con);
if(con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
cmd.Notification = null;
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
messages.Add(item: new ActivityLog
{
Activity = reader["Activity"] != DBNull.Value ? (string)reader["Activity"] : "",
LogDate = (DateTime)reader["LogDate"]
});
}
}
}
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(messages);
return json;
}
catch(Exception ex)
{
throw;
}
}
public static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= dependency_OnChange;
var activityHub = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
GetActivityLogs();
}
}
}
FIRST METHOD
First Solution change your javascript code like this. If this not works move to the second method:
$(function () {
var activityFromHub = $.connection.ActivityHub;
$.connection.hub.start().done(function () {
FetchLogs();
});
activityFromHub.client.displayLog = function () {
console.log('Hub Started');
FetchLogs();
}
});
SECOND METHOD:
Each client connecting to a hub passes a unique connection id. You can retrieve this value in the Context.ConnectionId property of the hub context. And i found there is nothing happening like this. You may try this solution.
I think the simplest solution for your question is to use groups.
http://www.asp.net/signalr/overview/guide-to-the-api/working-with-groups
Your hub class would contain methods to join a group:
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.Remove(Context.ConnectionId, groupName);
}
and your hub will be look like this:
public static void StartLogging(string groupName)
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<ActivityHub>();
context.Clients.Group(groupName).displayLog();
//calls the signalR client part to execute javascript method
//context.Clients.All.displayLog();
}
And change your javascript as like this:
$(function () {
var activityFromHub = $.connection.ActivityHub;
$.connection.hub.start().done(function () {
activityFromHub.server.joinGroup("Group1");
activityFromHub.server.StartLogging("Group1");
FetchLogs();
});
activityFromHub.client.displayLog = function () {
console.log('Hub Started');
FetchLogs();
}
});
I hope this will resolve your issue. If you are still facing issue. Please leave comments. Thank you.

can't receive data from post call in my controller

I have a html editor and I am trying to send the data via post call. I can see the data in javascript and it hits SendEmail method but in my controller request is empty. Why can't see the data in my controller?
function SelectedReceipientsViewModel() {
var self = this;
self.packageDataForEmail = function () {
var request= tinymce.get("mailTextArea").getContent();
return request;
};
self.submit = function () {
var request = self.packageDataForEmail();
$.post("SendEmail",request, function () {
}).done(function () {
}).fail(function () {
});
};
}
my controller:
[HttpPost]
public void SendEmail(string request)
{
string message = request;
......
...
}
I created DtoEblast and add my property inside. for some reason string did not work. anyways this is working code.
self.packageDataForEmail = function () {
var Request = function (tinymceText) {
this.TinymceText = tinymceText;
};
var tinymceText = tinymce.get("mailTextArea").getContent();
var request = new Request(tinymceText);
return request;
};
[HttpPost]
public void SendEmail(DtoEblast request)
{
string message = request.TinymceText;
and it was giving 500 error without this line
<script>tinymce.init({forced_root_block : "",selector:'textarea'});</script>

Model Id passed through to Angular Ctrl

I have a MVV view that used the Controller below, I need to get the product Id, ie Model.Id through to the controller somehow.
I have tried the $scope.init but it is coming through as null when I am making the first Ajax call, I suspect that this ajax get is kicking off before the init is fired and setting the product id, so the ajax fails as the productId is null when the call is made. I am new to angular so if its a schoolboy error I apologise !.
Controller and HTML are shown below.
angular.module('askQuestions', [])
.controller('questionController', function ($scope, $http) {
$scope.loading = true;
$scope.addMode = false;
$scope.replyMode = false;
$scope.parentClicked = 0;
$scope.init = function (productId) {
//This function is sort of private constructor for controller
$scope.productId = productId;
$scope.getUrl = '/Api/GetProductQuestions/' + $scope.productId;
};
//Used to display the data
//$http.get('/Api/GetAllManufacturers?apiToken=6a5ce02e-0506-0a41-2f50-37327080662f').success(function (data) {
$http.get($scope.getUrl).success(function (data) {
$scope.questions = data;
$scope.loading = false;
})
.error(function () {
$scope.error = "An Error has occured while loading questions!";
$scope.loading = false;
// alert($scope.getUrl);
});
});
<div data-ng-app data-ng-controller="questionController" ng-init="init('#Model.Id')" class="container">
Your $http.get is evaluated in the instantiation of the controller. The instantiation is before your init, so the ajax call is already being made. You can easily fix this by wrapping your $http.get also in a function:
$scope.init = function (productId) {
//This function is sort of private constructor for controller
$scope.productId = productId;
$scope.getUrl = '/Api/GetProductQuestions/' + $scope.productId;
getData();
};
var getData = function() {
$http.get($scope.getUrl)
.success(function (data) {
// success
$scope.questions = data;
})
.error(function () {
// error
$scope.error = "An Error has occured while loading questions!";
})
.finally(function () {
// always
$scope.loading = false;
});
}

How to call isValid() function in the viewmodel using knockout-validation

I have a viewmodel defined following:
var ViewModel = function() {
var self = this;
self.property1 = ko.observable().extend({ required: true });
self.property2 = ko.computed(function() {
return self.property1();
});
self.form_onsubmit = function (form) {
if (!self.isValid()) {
console.log("error");
}
return false;
};
};
$(function () {
ko.applyBindingsWithValidation(new ViewModel());
});
when i call the form_onsubmit function, an error occured:
TypeError: self.isValid is not a function
if (!self.isValid()) {
how to solve it, thanks^^^
add
self.errors = ko.validation.group(self);
to your viewmodel

Breeze js Non-EF hasServerMetadata

I'm running the following using Breeze.js with Asp.Net WebAPI. I can query my service using OData protocol and I can see JSON data in the response, but the .then() and .fail() callbacks aren't firing so the view model never gets the data. Is that because I'm missing the metadata?
/// <reference path="..\breeze.debug.js" />
(function (root) {
var dataService = new breeze.DataService({
serviceName: 'api/breezesample',
hasServerMetadata: false
});
var altMs = new breeze.MetadataStore({
namingConvention: breeze.NamingConvention.camelCase
});
var manager = new breeze.EntityManager({
dataService: dataService,
metadataStore: altMs
});
// define the viewmodel
var vm = {
todos: ko.observableArray(),
includeDone: ko.observable(false),
show: ko.observable(false)
};
// start fetching Todos
getTodos();
// re-query when "includeDone" checkbox changes
//vm.includeDone.subscribe(getTodos);
// bind view to the viewmodel
ko.applyBindings(vm);
/* Private functions */
// get Todos asynchronously
// returning a promise to wait for
function getTodos() {
var query = breeze.entityModel.EntityQuery.from("todos");
if (!vm.includeDone()) {
query = query.where("IsDone", "==", false);
}
return manager
.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
};
function querySucceeded(data) {
vm.todos.removeAll();
var todos = data.results;
todos.forEach(function (todo) {
vm.todos.push(todo);
});
vm.show(true); // show the view
}
function queryFailed(error) {
alert("Query failed: " + error.message);
}
}(window));
Try this code. You will also need to add your metadata to the 'altMs' via addEntityType method calls. Make sure you get the latest version of breeze as well, v.0.78.x. The 'breeze.entityModel' in your code is no longer needed.
var DataService = breeze.DataService;
var MetadataStore = breeze.MetadataStore;
var EntityManager = breeze.EntityManager;
var dataService = new DataService({
serviceName: altServiceName,
hasServerMetadata: false
});
var altMs = new MetadataStore({
namingConvention: NamingConvention.camelCase
});
return new EntityManager({
dataService: dataService,
metadataStore: altMs
});

Resources