Я работаю над добавлением SignalR в работающее приложение MVC, но я не разбираюсь в Javascript и не знаю, как написать его, чтобы отобразить то, что мне нужно. Я видел кучу обучающих программ с приложениями чата (отправка сообщения), но это не то, что мне нужно.
Что я хочу: Показать полную модель со всеми ее компонентами. Программа получает файл, который добавляет новое свойство в базу данных. Свойство должно отображаться со всеми его компонентами.
Вот пример модели (свойства) для отображения
public int WaterLevel { get; set; }
public int WindSpeed { get; set; }
public int NumberOfMachine { get; set; }
public int FoodLevel { get; set; }
HTML-страница - это HTML-страница по умолчанию, которая создается в Visual Studio: (Это то, что нужно обновить на веб-странице с помощью JavaScript)
<tbody>
@foreach (var item in Model)
{
<tr id="properties_display">
<td id="waterLevel">
@Html.DisplayFor(modelItem => item.WaterLevel)
</td>
<td id="windSpeed">
@Html.DisplayFor(modelItem => item.WindSpeed)
</td>
<td id="numberMachine">
@Html.DisplayFor(modelItem => item.NumberOfMachine)
</td>
<td id="foodLevel">
@Html.DisplayFor(modelItem => item.FoodLevel)
</td>
<td id="number">
@Html.DisplayFor(modelItem => item.Number)
</td>
</tr>
}
</tbody>
Наблюдатель (On_Change):
private readonly IHubContext<PropertyHub> _hubContext;
public MyFileWatcher(IHubContext<PropertyHub> hubContext)
{
_hubContext = hubContext;
//watcher stuff
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
DataAccess db = new DataAccess(MVCCoreAppDB);
string filePath = Path.GetFullPath(e.FullPath);
db.InsertData(filePath);
var propData = db.LoadData();
List<PropertyModel> properties = new List<PropertyModel>();
foreach (var row in propData)
{
properties.Add(new PropertyModel
{
WaterLevel = row.WaterLevel,
WindSpeed = row.WindSpeed,
NumberOfMachine = row.NumberOfMachine,
FoodLevel = row.FoodLevel
Number = row.Number
});
}
_hubContext.Clients.All.SendAsync("onFileChange", properties);
}
Класс наблюдателя ищет изменения в папке. Когда файл создается или изменяется, он вызывает 3 метода. Сначала он вставляет данные в базу данных, а затем загружает эти данные из базы данных и меняет тип, который будет использоваться.
Наконец, он вызывает концентратор, чтобы он знал, что есть изменения и что ему нужно обновить веб-страницу.
Это то, что я пробовал, и я получаю эффект в реальном времени, который мне нужен, но он не отображает нужную вещь:
"use strict";
let connection = new signalR.HubConnectionBuilder()
.withUrl("/propertyHub")
.build();
connection.on("onFileChange", function (properties) {
let tr = document.createElement("tr");
document.getElementById("properties_display").appendChild(tr);
let tdWaterLevel = document.createElement("td");
tdWaterLevel.textContent = properties[0];
document.getElementById("waterLevel").appendChild(tdWaterLevel);
let tdWindSpeed = document.createElement("td");
tdWindSpeed.textContent = properties[1];
document.getElementById("windSpeed").appendChild(tdWindSpeed);
let tdNumberMachine = document.createElement("td");
tdNumberMachine.textContent = properties[2];
document.getElementById("numberMachine").appendChild(tdNumberMachine);
let tdFoodLevel = document.createElement("td");
tdFoodLevel.textContent = properties[3];
document.getElementById("foodLevel").appendChild(tdFoodLevel);
let tdNumber = document.createElement("td");
tdNumber.textContent = properties[4];
document.getElementById("number").appendChild(tdNumber);
});
connection.start().then(function () { TestConnection(); }).catch(function(err)
{
return console.error(err.toString());
});
function TestConnection() {
connection.invoke("GetConnectionId").catch(function (err) {
return console.error(err.toString());
});
}
Как сейчас, он пишет в хороших столбцах, но не в конце таблицы и не записывает значения. Он пишет объект Object вместо числа. Кроме того, когда я пишу в JavaScript;
properties.WaterLevel //For example
Это пустое место вместо того, чтобы что-то писать.
//It does the same thing if I write properties [0].WaterLevel
Вывод перед обновлением: Вывод после обновления:
Требуемый выход:
Значение свойства в отладке после добавления нового файла:
Любая идея о том, как получить правильные значения в хорошем месте?
2 ответа
Основываясь на том, что у вас есть, посмотрите фрагмент. Ваш объект JavaScript - это массив, который содержит один объект.
var properties = [
{
"FoodLevel" : 48,
"Id":0,
"MachineID": "1234567",
"Number" : 0,
"NumberOfMachine" : 32,
"WaterLevel" : 54,
"WindSpeed" : 98
}
]
let tbody = document.getElementById("tableBody")
let tr = document.createElement("tr");
let tdWaterLevel = document.createElement("td");
tdWaterLevel.innerHTML = properties[0].WaterLevel;
tr.appendChild(tdWaterLevel);
let tdWindSpeed = document.createElement("td");
tdWindSpeed.innerHTML = properties[0].WindSpeed;
tr.appendChild(tdWindSpeed);
let tdNumberOfMachine = document.createElement("td");
tdNumberOfMachine.innerHTML = properties[0].NumberOfMachine;
tr.appendChild(tdNumberOfMachine);
let tdFoodLevel = document.createElement("td");
tdFoodLevel.innerHTML = properties[0].FoodLevel;
tr.appendChild(tdFoodLevel);
let tdNumber = document.createElement("td");
tdNumber.innerHTML = properties[0].Number;
tr.appendChild(tdNumber);
tbody.appendChild(tr);
<table>
<thead>
<th>Water Level</th>
<th>Wind Sepeed</th>
<th>Number Of Machines</th>
<th>Food Level</th>
<th>Number</th>
</thead>
<tbody id="tableBody">
<!-- other razor code : for each x in model bla bla -->
</tbody>
</table>
Вы передаете список клиенту, где, как я думаю, вы должны передавать только один объект типа списка, таким образом вам не нужно обращаться к объекту по индексу, и вы можете сделать это: properties.WaterLevel
Если вы намереваетесь обновить несколько объектов одновременно (имейте в виду, я не имею в виду вашу модель представления, которая уже представлена на этом этапе), то вы можете зациклить массив и последовательно добавить каждую строку.
Итак, жизненный цикл это:
- представление рендера со списком существующих объектов (для каждого в модели)
- клиент добавляет новый элемент
- сервер передает один новый элемент всем клиентам
- клиент обновляет существующее представление новым отдельным элементом
Я думаю, вы немного запутались в том, как работает таблица и строки таблицы. Прежде всего HTML должен выглядеть примерно так:
<tbody id="properties_display">
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.WaterLevel)
</td>
<td>
@Html.DisplayFor(modelItem => item.WindSpeed)
</td>
<td>
@Html.DisplayFor(modelItem => item.NumberOfMachine)
</td>
<td>
@Html.DisplayFor(modelItem => item.FoodLevel)
</td>
<td>
@Html.DisplayFor(modelItem => item.Number)
</td>
</tr>
}
</tbody>
id
должен быть уникальным для всей страницы, но вы создаете новую строку с одинаковыми идентификаторами для каждого элемента в вашей модели. Это нехорошая практика и может привести к путанице, какой элемент вы хотите добавить. Но это также означает, что у каждого элемента в свойстве должна быть своя собственная строка (tr), поэтому вы захотите вставлять новые строки вместо добавления к любым текущим, что вы и делаете, ссылаясь на идентификаторы в javascript.
На самом деле, поскольку вы, кажется, отправляете все данные обратно клиенту при изменении, тогда самым простым способом обновления было бы удалить все текущие строки и добавить все новые, что-то вроде этого:
connection.on("onFileChange", function (properties) {
let table = document.getElementById("properties_display");
// Remove all existing rows
while (table.firstChild) {
table.removeChild(table.firstChild);
}
// Add a new row for each item in properties
for (let i = 0; i < properties.length; i++) {
let tr = document.createElement("tr");
let tdWaterLevel = document.createElement("td");
tdWaterLevel.textContent = properties[i].waterLevel;
tr.appendChild(tdWaterLevel);
let tdWindSpeed = document.createElement("td");
tdWindSpeed.textContent = properties[i].windSpeed;
tr.appendChild(tdWindSpeed);
let tdNumberMachine = document.createElement("td");
tdNumberMachine.textContent = properties[i].numberMachine;
tr.appendChild(tdNumberMachine);
let tdFoodLevel = document.createElement("td");
tdFoodLevel.textContent = properties[i].foodLevel;
tr.appendChild(tdFoodLevel);
let tdNumber = document.createElement("td");
tdNumber.textContent = properties[i].number;
tr.appendChild(tdNumber);
table.appendChild(tr);
}
});
Я не проверял это, но это, вероятно, больше соответствует тому, что вы хотите. Вы передаете все свои элементы в JavaScript, поэтому он должен пройти через все элементы и получить их индивидуальные свойства. Возможно, вам придется убедиться, что данные вашего хаба правильно передаются в javascript. Если это не так, вам может потребоваться преобразовать в Json на сервере перед передачей, но я думаю, что SignalR автоматически обрабатывает эти вещи.
Вы упомянули, что properties.WaterLevel
не возвращает ничего, что имеет смысл, так как свойства были массивом, но если properties[0].WaterLevel
, то возможно, что-то еще, и я бы зарегистрировал объект свойств в javascript, чтобы увидеть, какой у вас сервер фактически переходит в браузер.
В качестве последнего замечания, удаление и замена всех строк, вероятно, не лучшая идея. Вы можете лучше использовать существующие строки и добавить необходимые или просто передать только измененные элементы с сервера, а не все. Просто некоторые мысли. Надеюсь это поможет.
Похожие вопросы
Новые вопросы
javascript
По вопросам программирования на ECMAScript (JavaScript/JS) и его различных диалектах/реализациях (кроме ActionScript). Обратите внимание, что JavaScript — это НЕ Java. Включите все теги, относящиеся к вашему вопросу: например, [node.js], [jQuery], [JSON], [ReactJS], [angular], [ember.js], [vue.js], [typescript], [стройный] и т. д.