cannot remove knockout observableArray item with SingalR - asp.net-mvc-4

I am struggling with two issues. The first one is that after I pushed a new item into observableArray and try to refresh the accordion. The new item did not show up in the accordion. But the producs().length increased by one.
this.hub.client.productAdded = function (p) {
products.push(new productListViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
//loadAccordion();
};
My second issue is that After SignalR deleted an item in the database and returned with the deleted object I tried to remove the deleted object from the observableArray. I have tried different ways and none of them work.
this.hub.client.productRemoved = function (deleted) {
//var deleted = ko.utils.arrayFilter(products(), function (item) {
// return item.id == deleted.id;
//})[0];
products.remove(function (item) { return item.id == deleted.id; });
//products.remove(deleted);
$("#accordion").accordion("refresh");
};
What do I miss here? Below is the whole page code for reference
#{
ViewBag.Title = "SignalR";
}
<h2>SignalR</h2>
<div id="error"></div>
<h2>Add Product</h2>
<form data-bind="submit: addProduct">
<input data-bind="value: newProductText" class="ui-corner-all" placeholder="New product name?" />
<input type="submit" class="ui-button" value="Add Product" />
</form>
<h2>Our Products</h2>
listed: <b data-bind="text: productCount"></b> product(s)
#*<div id="accordion" data-bind="template: {name: productTemplate, foreach: products }, visible: products.Length > 0"></div>*#
<div id="accordion" data-bind='template: {name: "product-template", foreach: products }'></div>
<script type="text/html" id="product-template">
<h3 data-bind="text: name"></h3>
<div>
<input type="button" class="ui-button" value="Remove Rroduct" data-bind="click: removeProduct" />
</div>
</script>
<span data-bind="visible: productCount() == 0">What? No products?</span>
#section Scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/signalr")
<script src="/Scripts/jquery.signalR-2.0.1.min.js" type="text/javascript"></script>
<script src="~/signalr/hubs" type="text/javascript"></script>
<script src="/Scripts/jquery.livequery.min.js"></script>
<style>
#accordion {width: 300px;}
#accordion h3 { padding-left: 30px}
</style>
<script>
function productViewModel(id, name, ownerViewModel) {
this.id = ko.observable(id);
this.name = ko.observable(name);
var self = this;
this.removeProduct = function () { ownerViewModel.removeProduct( id); };
this.name.subscribe(function (newValue) {
ownerViewModel.updateProduct(ko.toJS(self));
});
}
function productListViewModel() {
this.hub = $.connection.products;
this.products = ko.observableArray([]);
this.newProductText = ko.observable();
chat = this.hub
var products = this.products;
var self = this;
// Get All
this.init = function () {
this.hub.server.getAll();
}
this.hub.client.productAll = function (allProducts) {
//var mappedProducts = $.map(allProducts, function (item) {
// return new productViewModel(item.id, item.name, self);
//});
//products(mappedProducts);
$.each(allProducts, function (index, item) {
products.push(new productViewModel(item.id, item.Name, self));
});
loadAccordion();
};
this.hub.reportError = function (error) {
$("#error").text(error);
};
$.connection.hub.error(function (error) {
console.log('SignalR error: ' + error)
});
this.hub.client.productAdded = function (p) {
products.push(new productListViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
//loadAccordion();
};
this.hub.client.productRemoved = function (deleted) {
//var deleted = ko.utils.arrayFilter(products(), function (item) {
// return item.id == deleted.id;
//})[0];
products.remove(function (item) { return item.id == deleted.id; });
//products.remove(deleted);
$("#accordion").accordion("refresh");
};
// Commands
this.addProduct = function () {
var p = { "Name": this.newProductText() };
this.hub.server.add(p).done(function () { }).fail(function (e) { alert(e); });
this.newProductText("");
};
this.removeProduct = function (id) {
this.hub.server.remove(id).done(function () { alert("aa"); }).fail(function (e) { alert(e+" aa"); });
};
this.productCount = ko.dependentObservable(function () {
return products().length;
}, this);
}
function loadAccordion() {
$("#accordion").accordion({ event: "mouseover" });
}
$(function () {
var viewModel = new productListViewModel();
ko.applyBindings(viewModel);
// connect SinalR
$.connection.hub.start(function () { viewModel.init(); });
//$.connection.hub.start(function () { chat.server.getAll(); });
});
</script>
}

To solve your add problem: you are creating a new productListViewModel but you need to add a new productViewModel, so you just need to create the correct viewmodel:
this.hub.client.productAdded = function (p) {
products.push(new productViewModel(p.id, p.Name, self));
$("#accordion").accordion("refresh");
};
To solve your delete problem: in your productViewModel the id is a ko.observable so you need to write item.id() to access its value in the remove function:
this.hub.client.productRemoved = function (deleted) {
products.remove(function (item) { return item.id() == deleted.id; });
$("#accordion").accordion("refresh");
};

Related

How can I make my WebRTC is working properly

Now I am building a video call site with WebRTC. But it recognize camera and ask to allow camera.
When I allow camera it shows nothing.
I will write down my code here.
<body onload="init()">
<div class="row">
<div class="col-8">
<form action="#">
<h5>Current Room ID: <span id="curr_room_id"></span><br/></h5>
<input id="new_room_id" name="room" type="text" placeholder="Enter a room id to connect..." style="padding: 5px"/>
<input type="submit" id="connect" value="Connect" />
</form>
<input id="call" type="submit" value="Call" disabled="true"/>
<input id="end" type="submit" value="End Call"disabled="true"/>
</div>
<div class="col-4" id="google_translate_element"></div>
</div>
<h1>local</h1>
<video id="local_video" width="400px" style="border: 1px solid black;"></video>
<h1>remote</h1>
<video id="remote_video" width="400px" style="border: 1px solid black;"></video>
<script src="/socket.io/socket.io.js"></script>
<script src="../scripts/video-client.js"></script>
<script src="../scripts/video-room.js"></script>
<script>
function init() {
console.log("document loaded");
call.removeAttribute("disabled");
call.addEventListener("click", function(){
createPeerConnection();
call.setAttribute("disabled", true);
end.removeAttribute("disabled");
});
end.addEventListener("click", function() {
// change rooms
end.setAttribute("disabled", true);
call.removeAttribute("disabled");
});
}
</script>
</body>
I think it is because of not showing video stream to webview. But i didn't find nothing. Please tell me.
And here is video-client.js
console.log("loaded");
var socket = io();
var local = document.getElementById("local_video");
var remote = document.getElementById("remote_video");
var call = document.getElementById("call");
var end = document.getElementById("end");
var room_id = document.getElementById("curr_room_id");
var localStream = null, remoteStream = null;
var config = {'iceServers' : [{'url' : 'stun:stun.l.google.com:19302'}]};
var pc;
/////////////////////////////////
function createPeerConnection() {
try {
pc = new RTCPeerConnection(config);
pc.onicecandidate = handleIceCandidate;
pc.onaddstream = handleRemoteStreamAdded;
pc.onremovestream = handleRemoteStreamRemoved;
pc.onnegotiationneeded = handleNegotiationNeeded;
getUserMedia(displayLocalVideo);
pc.addStream(localStream);
console.log("Created RTCPeerConnection");
} catch (e) {
console.log("Failed to create PeerConnection: " + e.message);
return;
}
}
function handleIceCandidate(event) {
console.log("handleIceCandidate event: " + event);
if(event.candidate) {
sendMessage(JSON.stringify({'candidate': evt.candidate}));
} else {
consolel.log("End of ice candidates");
}
}
function handleRemoteStreamAdded(event) {
console.log("Remote stream added");
displayRemoteVideo(event.stream);
call.setAttribute("disabled", true);
end.removeAttribute("disabled");
}
function handleRemoteStreamRemoved(event) {
console.log("Remote stream removed: " + event);
end.setAttribute("disabled", true);
call.removeAttribute("disabled");
local.src = "";
remote.src = "";
}
function handleNegotiationNeeded() {
pc.createOffer(localDescCreated, logError);
}
function localDescCreated(desc) {
pc.setLocalDescription(desc, function() {
sendMessage(JSON.stringify({'sdp': pc.localDescription}));
}, logError);
}
call.onclick(function(){
createPeerConnection();
});
/////////////////////////////////
function getUserMedia(callback) {
navigator.mediaDevices.getUserMedia({video: true, audio: false}).then(
function(stream) {
callback(stream);
return stream;
}).catch(logError);
}
function displayLocalVideo(stream) {
localStream = stream;
local.src = window.URL.createObjectURL(stream);
local.play();
}
function displayRemoteVideo(stream) {
remoteStream = stream;
remote.src = window.URL.createObjectURL(stream);
remote.play();
}
function logError(error) {
console.log(error);
}
function sendMessage(message) {
socket.emit("message", message);
}
/////// receiving stream //////////
socket.on("message", function(evt){
if(!pc)
createPeerConnection();
var message = JSON.parse(evt.data);
if(message.sdp) {
pc.setRemoteDescription(new RTCSessionDescription(), function() {
if(pc.remoteDescription.type == 'offer')
pc.createAnswer(localDescCreated, logError);
}, logError);
} else {
pc.addIceCandidate(new RTCIceCandidate(message.candidate));
}
});
I think call.onclick() has to work properly for video streaming but it does not also.
You are not seeing your video because you are not using the stream that getUserMedia returns. You need to attach that stream to the video.

Vue.js / How to access the function in another component

I just started learning Vue.js. I need to call the function in another component in my project. When I add new data to the table with createAnnouncement.vue, I want to go into announcement.vue and call the queryAnnouncement function. How can I do that? I would appreciate if you could help, please explain with a sample. Or edit my codes.
Announcement.Vue template:
<template>
// more div or not important template code
<div class="dataTables_filter" style="margin-bottom:10px">
<label>
<input class="form-control form-control-sm" placeholder="Search" aria-controls="m_table_1" type="search" v-model="searchField" #change="filter()">
</label>
<a style="float:right" href="#" data-target="#create-announcement-modal" data-toggle="modal" class="btn btn-primary">
<i class="">Add</i>
</a>
</div>
// more div or not important template code
</template>
Announcement.Vue Script Code:
<script>
import toastr from "toastr";
export default {
name: 'announcement',
data() {
return {
announcements: [],
searchField: "",
deleteCsrfToken: this.$root.csrfTokens["deleteAnnouncement"]
}
},
beforeMount: async function () {
await this.queryAnnouncements();
},
methods: {
filter: async function () {
await this.queryAnnouncements(this.searchField);
},
queryAnnouncements: async function (filter, pageSize, pageIndex, sortBy, sortType) {
var data = {
"query[general-filter]": filter,
"pagination[perpage]": !!pageSize ? pageSize : 10,
"pagination[page]": !!pageIndex ? pageIndex : 1,
"sort[field]": sortType,
"sort[sort]": !!sortBy ? sortBy : "asc"
};
let response = await axios
.get("/Announcement/QueryAnnouncements", { params: data })
this.announcements = response.data.data;
},
}
}
createAnnouncement.vue code:
<template>
<button #click="createAnnouncement()" v-bind:disabled="contentDetail === ''" class="btn btn-success">
Save</button>
//not important template codes
<template>
<script>
import toastr from "toastr";
export default {
name: 'create-announcement',
data() {
return {
contentDetail: "",
createCsrfToken: this.$root.csrfTokens["createAnnouncement"],
}
},
methods: {
createAnnouncement: async function () {
var self = this;
var data = {
content: this.contentDetail,
};
let response = await axios
.post("/Announcement/createAnnouncement",
data,
{
headers: {
RequestVerificationToken: self.createCsrfToken
}
})
if (response.status == 200) {
$("#create-announcement-modal .close").click()
$("#create-announcement-form").trigger('reset');
toastr["success"]("Kayıt başarıyla eklendi!", "Başarılı!");
self.contentDetail = "";
}
else {
toastr["warning"]("Hata", "Kayıt Eklenemedi.");
}
}
},
}
</script>
Please show with sample or arrangement, my english is not very good. Thanks.

changing the value onclick in react-js

output look like this when i click change text button it should replace the text (TodoApplication) with that value if it is empty value(should replace empty heading) the value was not changing in this code! can anyone edit the code to get a solution!
var TodoApp = React.createClass({
getInitialState: function() {
return {items: []};
},
updateItems: function(newItem) {
var allItems = this.state.items.concat([newItem]);
this.setState({items: allItems});
},
render: function() {
return (
<div>
<TodoBanner/>
<TodoList items={this.state.items}/>
<TodoForm onFormSubmit={this.updateItems}/>
</div>
);
}
});
var TodoBanner = React.createClass({
render: function() {
return (
<div className="container">
<h3>TODO Application</h3>
</div>
);
}
});
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText) {
return (
<TodoListItem>{itemText}
</TodoListItem>
);
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoListItem = React.createClass({
render: function() {
return (
<li>{this.props.children}</li>
);
}
});
var TodoForm = React.createClass({
getInitialState: function() {
return {item: ''};
},
handleSubmit: function(e) {
e.preventDefault();
this.props.onFormSubmit(this.state.item);
this.setState({item: ''});
React.findDOMNode(this.refs.item).focus();
return;
},
onChange: function(e) {
this.setState({item: e.target.value});
},
render: function() {
return (
<div className="container">
<form onSubmit={this.handleSubmit}>
<input type='text' ref='item' onChange={this.onChange} value={this.state.item}/>
<input type='submit' value='Add' className="btn btn-success"/><br/>
<input type='text' ref='item' onChange={this.onChange} value={this.state.item}/>
<input type='submit' value='Change Text' className="btn btn-success"/>
</form>
</div>
);
}
});
ReactDOM.render(
<TodoApp/>, document.getElementById('todo'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="todo" />
I'm afraid I didn't get what you mean. Did you mean something like this?
https://jsfiddle.net/alfrcr/upzqf067/1/
If so, in order to change the 'Todo Application' text, you should send the form state to the upper component.
So TodoBanner can access 'that form state' as a props. (See the example code)

JqWidget tabs - dynamically add tab with ajax content

I want create a dynamic on click append data to tab but I get in the tab undefined. Could you tell me whats wrong? Not quite sure what is the case,
My js
<script type="text/javascript">
$(document).ready(function () {
// Create jqxTabs.
$('#jqxTabs').jqxTabs({ width: 580, height: 200,showCloseButtons: true });
var length = $('#jqxTabs').jqxTabs('length') + 1;
var loadPage = function (url) {
$.get(url, function (data) {
data;
// console.log( $('#content' + length ).text(data));
// console.log(data);
});
}
$('div.s span').click(function() {
var getvalue = $(this).attr('rel');
$('#jqxTabs').jqxTabs('addFirst', 'Sample title',loadPage(getvalue).text());
$('#jqxTabs').jqxTabs('ensureVisible', -1);
});
// $('#jqxTabs').on('selected', function (event) {
// var pageIndex = event.args.item + 1;
// loadPage('pages/ajax' + pageIndex + '.htm', pageIndex);
// });
});
</script>
My html
<div class="s">
<span rel="gen.php">Load</span>
</div>
<div id='jqxWidget'>
<div id='jqxTabs'>
<ul>
</ul>
</div>
</div>
So first check the right syntax for tab control:
HTML:
....
<div id='jqxTabs'>
<ul>
<li></li>
</ul>
<div></div>
</div>
Javascript:
// Create jqxTabs.
$('#jqxTabs').jqxTabs({ width: 580, height: 200, showCloseButtons: true });
$('#jqxTabs').jqxTabs("removeFirst"); //here removes the empty tab
//here the function must return the content, and the ajax must be async false for this purpose
var loadPage = function (url) {
var result = null;
$.ajax({
url: url,
type: 'get',
dataType: 'html',
async: false,
success: function(data) {
result = data;
}
});
return result;
}
$('div.s span').click(function() {
var getvalue = $(this).attr('rel');
$('#jqxTabs').jqxTabs('addFirst', 'Sample title', loadPage(getvalue));
$('#jqxTabs').jqxTabs('ensureVisible', -1);
});
For better understanding check: http://jsfiddle.net/charlesrv/h4573ykv/1/
EDIT: For the new condition, use a custom attribute so checking would be easier:
$('div.s span').click(function() {
var getvalue = $(this).attr('rel');
var opened = $(this).attr('opened');
if (!opened) {
$(this).attr('opened', true);
$('#jqxTabs').jqxTabs('addFirst', 'Sample title', loadPage(getvalue));
$('#jqxTabs').jqxTabs('ensureVisible', -1);
}
});

sharepoint 2013 _api/$metadata error 'A nonnullable DataProperty cannot have a null defaultValue. Name: undefined'

I try to use sharepoint 2013 rest api with breezejs.
I get error
A nonnullable DataProperty cannot have a null defaultValue. Name: undefined
when breezejs validates returned metadata (_api/$metadata).
With breeze.EntityManager("/_vti_bin/listdata.svc/") all works.
What are the ways to fix it?
<script src="/_layouts/15/SharePointProject7/scripts/angular.min.js"></script>
<script src="/_layouts/15/SharePointProject7/scripts/q.min.js"></script>
<script src="/_layouts/15/SharePointProject7/scripts/datajs-1.1.1.min.js"></script>
<script src="/_layouts/15/SharePointProject7/scripts/breeze.min.js"></script>
<script src="/_layouts/15/SharePointProject7/scripts/breeze.toq.js"></script>
<script src="/_layouts/15/SharePointProject7/scripts/app.js"></script>
<div data-ng-app="app">
<div data-ng-controller="Ctrl2">
<ul>
<li data-ng-repeat="c in customers"><input type="text" data-ng-model="c.Title" /></li>
</ul>
<button type="button" data-ng-click="save()">Save</button>
</div>
</div>
var app = angular.module('app', []);
app.run(['$q', '$rootScope', function ($q, $rootScope) {
breeze.core.extendQ($rootScope, $q);
}]);
app.service('listData', function () {
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager("/_api/");
var changes;
this.getItems = function () {
var query = breeze.EntityQuery.from("Lists");
return manager.executeQuery(query).to$q();
};
this.saveItems = function () {
if (manager.hasChanges()) {
changes = manager.getChanges();
manager.saveChanges().to$q(saveSucceeded, saveFailed);
}
else {
alert("Nothing to save");
};
};
function saveSucceeded() {
alert("OK");
};
function saveFailed(error) {
alert(error.message);
};
});
app.controller('Ctrl2', function ($scope, listData) {
function initialize() {
listData.getItems().then(querySucceeded, _queryFailed);
};
function querySucceeded(data) {
$scope.customers = data.results;
}
function _queryFailed(error) {
alert(error.message);
}
$scope.save = function () {
listData.saveItems();
};
initialize();
});
It is better to hand write the entity configuration as the SP metadata can be huge and it is not a good idea to pull it down at the beginning of the app load.
First get the SharePoint breeze adapter from breeze labs.
Full details here http://www.andrewconnell.com/blog/getting-breezejs-to-work-with-the-sharepoint-2013-rest-api
That post goes step by step on getting this working.