Я работаю над добавлением 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

Вывод перед обновлением: введите описание изображения здесь Вывод после обновления: Вывод после обновления: Требуемый выход: введите описание изображения здесь Значение свойства в отладке после добавления нового файла: введите описание изображения здесь

Любая идея о том, как получить правильные значения в хорошем месте?

1
Michaeldc 15 Авг 2019 в 16:09

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

Если вы намереваетесь обновить несколько объектов одновременно (имейте в виду, я не имею в виду вашу модель представления, которая уже представлена на этом этапе), то вы можете зациклить массив и последовательно добавить каждую строку.

Итак, жизненный цикл это:

  • представление рендера со списком существующих объектов (для каждого в модели)
  • клиент добавляет новый элемент
  • сервер передает один новый элемент всем клиентам
  • клиент обновляет существующее представление новым отдельным элементом
1
Vince 15 Авг 2019 в 15:24

Я думаю, вы немного запутались в том, как работает таблица и строки таблицы. Прежде всего 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, чтобы увидеть, какой у вас сервер фактически переходит в браузер.

В качестве последнего замечания, удаление и замена всех строк, вероятно, не лучшая идея. Вы можете лучше использовать существующие строки и добавить необходимые или просто передать только измененные элементы с сервера, а не все. Просто некоторые мысли. Надеюсь это поможет.

1
Michaeldc 15 Авг 2019 в 17:40