2013-12-16 2 views
0

Я работаю над профилем для пользователей на моем веб-сайте ASP.NET MVC. И у меня есть много свойств (флажки, выпадающих и т.д.), как:Сохранение свойств «на лету»

  • Времени зона
  • DST
  • Настройка электронной почты

я могу создать свою собственную модель для обработки всех из них, как это :

public class ProfileViewModel 
{ 
    public TimeZoneOptions TimeZone { get; set; } 
    public DstOptions Dst { get; set; } // Daylight Saving Time 
    public bool EmailSettings1 { get; set; } 
    public bool EmailSettings2 { get; set; } 
    // ... 
    public bool EmailSettings22 { get; set; } 
} 

Мои свойства модели не связаны друг с другом. Поэтому мне не нужно звонить ModelState.IsValid. Кажется, моя модель всегда будет действительной.

Если я следовать стандартному способу сохранения модели в ASP.NET MVC, это заставит мой клиент нажать дважды:

  1. Изменить свойство
  2. Нажмите кнопку Сохранить

Но я хочу, чтобы они сделали это одним щелчком мыши. Как на этом скриншоте:

enter image description here

Я хочу, чтобы каждое свойство быть помечены «Изменения сохранены», когда пользователь нажимает на них. И Я хочу достичь этого с минимальным количеством кода. Похоже, что это легко сделать с помощью:

  • JQuery только

или

  • Knockout.js

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

Я не знаю, как сделать это с помощью нокаута, может быть какая-то привязка необходима для обновления элемента, когда он сохраняется так:

<span data-bind="display-when-saved-for-property: EmailSettings1"></span> 

???

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

+0

Просто есть OnChange событие для ваших флажков, который имеет АЯКС вызов вашим контроллер. Ваш контроллер сохранит данные, а обратный вызов успеха ajax отобразит измененные сообщения. Вот как я это сделаю. Дайте мне знать, если вы хотите получить более подробную информацию – heymega

+0

@heymega, спасибо. И как определить, какое свойство было изменено? Я должен представить всю модель контроллеру, не так ли? Таким образом, это уникальный URL-адрес ajax для сохранения модели для всех свойств. Как я могу отобразить «Сохраненные изменения» для определенного свойства? –

+1

Дайте мне 10 минут, я пишу код для вас – heymega

ответ

1

Я понимаю, что у вас есть список пользовательских настроек, которые будут отображаться как checkbox или dropdownlist.
Если это так, вы правы, что KnockoutJS более изящный способ (у меня была такая же проблема, прежде чем у меня есть кнопка сохранения, Мне повезло). Давайте посмотрим, что у нас есть:
У вас есть модель с главным образом bool свойствами, то, без сомнения, вы должны использовать KnockoutJS mapping plugin. Зачем? все, что мы собираемся сделать, это просто:

  1. Напишите HTML-разметку view.
  2. Для первой загрузки из наших view, сделать запрос AJAX, чтобы получить конфигурацию профиля пользователя, а затем с помощью mapping plugin преобразовать полученные данные в ViewModel и привязать его к нашим view (все это без необходимости писать на ViewModel по Ourself, которые означают, если ViewModel на сервере изменилось, нам просто нужно изменить только view).
  3. Для каждого checkbox или dropdownlist add change обработчик события (с использованием jQuery).
  4. change функция просто преобразовать наши переплетены ViewModel в JSON строку снова с помощью mapping plugin (только одна строка кода)
  5. Наконец сделал другой запрос AJAX, чтобы сохранить изменения.

Чтобы показать сообщение «Изменения сохранены», вы можете просто передать refrence вызывающего ввода и использовать немного магии jQuery, добавив ваше сообщение.

Update:
Вы могли должны быть выглядеть следующим образом (или, может быть, лучше, чем моя):

var UserProfile; 
$(document).ready(function() { 
    $('#ViewContainer input:checkbox').change(function (event) { 
     SaveUserProfile(event); 
    }); 
    IntializeUserProfile(); 
}); 

function IntializeUserProfile() { 
    // Show spinner 
    $.ajax({ 
     type: "POST", 
     url: URL_To_Get_User_Profile, 
     data: UserId, // in case of you need to pass data. 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     success: function(data) { 
      UserProfile = ko.mapping.fromJSON(data); //ko.mapping.fromJS($.parseJSON(msg)); 
      ko.applyBindings(UserProfile, selector); 
      // Hide Spinner 
     } 
    }); 
} 

function SaveUserProfile(event) { 
    // Show Spinner 
    var model = ko.toJSON(ko.mapping.toJS(UserProfile)); 
    event = event || window.event; 
    target = event.target || event.srcElement; 
    $.ajax({ 
     type: "POST", 
     url: URL_To_Save_UserProfile, 
     data: model, 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     success: function(data) { 
      // Hide Spinner 

      // here you have the caller input ==>target. 
      // for example, you can get it's parent to append your message 
      // or just show message in the page as notification. 
     } 
    }); 
} 
+0

Спасибо, это точно, как я думаю, что он должен работать. Но! Если я использую плагин сопоставления, как я могу передать ссылку на вызывающий вход? Есть ли способ сделать это автоматически? И как я могу отображать «Изменения сохранены» только в случае успеха? –

+0

@RomanPushkin проверить мое обновление –

3

Я думаю, что он может быть реализован с нокаутом + jQuery. С нокаутом очень легко создать приложение с изменением макета (как в вашем случае). JQuery в вашем случае требуется для асинхронных запросов.

Так, ViewModel:

var ViewModel = function(data) { 
    var self = this; 
    var _isCurrentSavingProp = null; 

    self.EmailSettings1 = ko.observable(data.EmailSettings1); 
    self.IsEmailSettings1Saved = ko.observable(); 
    ... another props 

    self.EmailSettings1.subscribe(function(val) {    
     isCurrentSavingProp = self.IsEmailSettings1Saved; 
     self.save(); 
    }); 
    ... another subscribers 

    self.save = function() { 
     isCurrentSavingProp(false); 
     $.post(url, ko.toJSON(self), function() { 
      isCurrentSavingProp(true); 
     }) 
    } 
} 

Html:

<span data-bind="visible: IsEmailSettings1Saved" style="display: none"></span> 
<input type="checkbox" data-bind="value: EmailSettings1" /> 
... etc.. 
+0

+1, но в этом случае мы должны написать минимум 5 строк кода для каждого свойства. Все в порядке, если у меня их мало. Но что, если у меня их много? Что делать, если у меня много форм, и не только этот? Мой код очень скоро станет неподъемным. Поэтому я не могу принять это как решение, извините. Я думаю, что это можно сделать с помощью каких-либо привязок, но я не уверен, что это возможно. –

+0

Я предложил решение для вашей текущей реализации. Если бы вы спросили, как улучшить свое решение, я бы предложил, не создавайте поле bool для каждой настройки, а храните их в массиве. В этом случае размер кода сервера и клиента будет минимизирован. – alexmac

+0

О нет, я не говорю о байтах, переданных между клиентом и сервером. Речь идет об ремонтопригодности. Если у меня много свойств, я должен написать «isCurrentSavingProp = self.IsEmailSettings1Saved» для каждого из них вручную. Это довольно неэффективно и должно быть оптимизировано. –

1

Ok ваша модель должна быть что-то вроде этого.

public class MyModel 
{ 

    public bool? Friends { get; set; } 
    public bool? Photos { get; set; } 
    public string Car { get; set; } 

} 

Ваш метод контроллера принимает экземпляр вашей модели. Пока ваш запрос ajax имеет имя данных, которое соответствует имени свойства в вашей модели, оно будет связываться.

public void UpdateValues(MyModel model) 
    { 

     if(model.Friends != null) 
     { 
      //Save 
     } 
     if (model.Photos != null) 
     { 
      //Save 
     } 
     if (model.Car != null) 
     { 
      //Save 
     } 


    } 

Допустим, ваш HTML разметка как этот

<div id="checkbox-container"> 
    <div>  
     <label> 
      <input type="checkbox" name="friends" /> 
     My Friends</label> 
    </div> 
    <div> 
     <label><input type="checkbox" name="photos" />My Photos</label> 
    </div> 
    <select id="car-dropdown"> 
     <option value="volvo">Volvo</option> 
     <option value="saab">Saab</option> 
     <option value="mercedes">Mercedes</option> 
     <option value="audi">Audi</option> 
    </select> 
</div> 

А вот JQuery ....

$('#checkbox-container input:checkbox').change(function() { 
    //Gets the property name we will bind 
    var field = $(this).attr("name"); 
    var isChecked = $(this).prop("checked"); 

    var data = {}; 
    data[field] = isChecked; 

    requestBuilder(data); 

}); 

//New method for our dropdown 
$('#car-dropdown').change(function() 
{ 


    var data = {}; 
    data['Car'] = $(this).val(); 

    requestBuilder(data); 


}); 


function requestBuilder(data) 
{ 

    //Ajax Request 
    $.ajax({ 
    //Change url to match your controller 
    url:"/Controller/UpdateValues/", 
    data:data, 
    type:"POST", 
    success:function(response) 
    { 
     alert("Change Saved") 
    } 
    }); 

} 

Обратите внимание, что мы передаем имя = "" атрибут над , Это соответствует названию, которое у нас есть в нашей модели, поэтому оно будет связываться :)

Сообщите мне, если вам нужно, чтобы я расширил любой элемент. Я также создал jsfiddle для кода переднего конца - http://jsfiddle.net/8tKBx/

Удачи вам!

+0

Хорошо, спасибо! И теперь я хочу, чтобы «Сохраненные изменения» отображались возле свойства clicked. Например, если я нажимаю «Мои друзья», я хочу, чтобы «Изменения были сохранены» отображались сразу после этого элемента. Но только в случае успеха. И что, если у меня есть раскрывающийся список? Я думаю, мы не можем отправить только одно свойство, было бы проще отправить всю модель на сервер. –

+0

Theres несколько разных способов сделать это. Вот довольно изменение, которое вложил я, но вы можете поэкспериментировать и сделать его своим. http://jsfiddle.net/8tKBx/4/. Я отредактирую свой оригинальный ответ, чтобы включить раскрывающийся список. gimme 5 mins – heymega

Смежные вопросы